Libinfo-278.0.3.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_utils.c
1 /*
2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <mach/mach.h>
29 #include <servers/bootstrap.h>
30 #include <pthread.h>
31 #include <errno.h>
32 #include <notify.h>
33 #include <syslog.h>
34 #include <unistd.h>
35 #ifdef DEBUG
36 #include <asl.h>
37 #endif
38 #include "lu_utils.h"
39 #include "netdb_async.h"
40 #include "DSlibinfoMIG.h"
41 #include "DSlibinfoMIGAsyncReply.h"
42
43 #define MAX_LOOKUP_ATTEMPTS 10
44 #define _LU_MAXLUSTRLEN 256
45 #define QBUF_SIZE 16384
46 #define KVBUF_START_SIZE 128
47
48 #define LI_MESSAGE_SEND_ID 4241776
49 #define LI_MESSAGE_REPLY_ID 4241876
50
51 #define ILS_MAGIC_SIZE 8
52 #define ILS_MAGIC "ILSMAGIC"
53
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"
59
60 /* GLOBAL */
61 uint32_t gL1CacheEnabled = 1;
62
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 };
65
66 static pthread_key_t _info_key = 0;
67 static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
68
69 static pthread_mutex_t _notify_lock = PTHREAD_MUTEX_INITIALIZER;
70 static int _L1_notify_token[] =
71 {
72 -1, /* global */
73 -1, /* group */
74 -1, /* host */
75 -1, /* service */
76 -1 /* user */
77 };
78
79 struct _li_data_s
80 {
81 uint32_t icount;
82 uint32_t *ikey;
83 void **idata;
84 };
85
86 typedef struct _li_async_request_s
87 {
88 mach_port_t reply_port;
89 uint32_t retry;
90 uint32_t proc;
91 void *context;
92 void *callback;
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;
97 vm_address_t ooreply;
98 mach_msg_type_number_t ooreplyCnt;
99 security_token_t token;
100 struct _li_async_request_s *next;
101 } _li_async_request_t;
102
103 static pthread_mutex_t _li_worklist_lock = PTHREAD_MUTEX_INITIALIZER;
104 static _li_async_request_t *_li_worklist = NULL;
105
106 /* Send an asynchronous query message. */
107 static kern_return_t
108 _LI_async_send(_li_async_request_t *r)
109 {
110 mach_msg_return_t status;
111 mach_vm_address_t cb;
112
113 if (r == NULL) return KERN_FAILURE;
114
115 if (r->retry == 0) return MIG_SERVER_DIED;
116 r->retry--;
117
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);
120
121 if (status == MACH_SEND_INVALID_REPLY)
122 {
123 mach_port_mod_refs(mach_task_self(), r->reply_port, MACH_PORT_RIGHT_RECEIVE, -1);
124 r->reply_port = MACH_PORT_NULL;
125 }
126
127 return status;
128 }
129
130 static _li_async_request_t *
131 _LI_worklist_remove(mach_port_t p)
132 {
133 _li_async_request_t *r, *n;
134
135 if (p == MACH_PORT_NULL) return NULL;
136 if (_li_worklist == NULL) return NULL;
137
138 pthread_mutex_lock(&_li_worklist_lock);
139
140 if (_li_worklist->reply_port == p)
141 {
142 r = _li_worklist;
143 _li_worklist = r->next;
144 pthread_mutex_unlock(&_li_worklist_lock);
145 return r;
146 }
147
148 for (r = _li_worklist; r != NULL; r = r->next)
149 {
150 n = r->next;
151 if (n == NULL) break;
152
153 if (n->reply_port == p)
154 {
155 r->next = n->next;
156 pthread_mutex_unlock(&_li_worklist_lock);
157 return n;
158 }
159 }
160
161 pthread_mutex_unlock(&_li_worklist_lock);
162 return NULL;
163 }
164
165 static _li_async_request_t *
166 _LI_worklist_find(mach_port_t p)
167 {
168 _li_async_request_t *r;
169
170 if (p == MACH_PORT_NULL) return NULL;
171 if (_li_worklist == NULL) return NULL;
172
173 pthread_mutex_lock(&_li_worklist_lock);
174
175 for (r = _li_worklist; r != NULL; r = r->next)
176 {
177 if (r->reply_port == p)
178 {
179 pthread_mutex_unlock(&_li_worklist_lock);
180 return r;
181 }
182 }
183
184 pthread_mutex_unlock(&_li_worklist_lock);
185 return NULL;
186 }
187
188 static void
189 _LI_free_request(_li_async_request_t *r)
190 {
191 if (r == NULL) return;
192
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;
195
196 free(r);
197 }
198
199 /*
200 * This is a callback for DSLibinfoMIGAsyncReplyServer.c
201 */
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)
204 {
205 _li_async_request_t *r;
206
207 r = _LI_worklist_find(server);
208
209 if (r != NULL)
210 {
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;
216 }
217 else if (ooreplyCnt != 0)
218 {
219 vm_deallocate(mach_task_self(), ooreply, ooreplyCnt);
220 }
221
222 return KERN_SUCCESS;
223 }
224
225 /* Receive an asynchronous reply message. */
226 kern_return_t
227 LI_async_receive(mach_port_t p, kvarray_t **reply)
228 {
229 kern_return_t status;
230 _li_async_request_t *r;
231 kvbuf_t *out;
232 int flags;
233
234 flags = MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
235
236 /* use mach_msg_server_once to do the work here */
237 status = mach_msg_server_once(DSlibinfoMIGAsyncReply_server, 65536, p, flags);
238
239 if (status != KERN_SUCCESS) return status;
240
241 r = _LI_worklist_remove(p);
242 if (r == NULL) return KERN_FAILURE;
243
244 out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
245 if (out == NULL)
246 {
247 if (r->ooreplyCnt > 0) vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
248 return KERN_FAILURE;
249 }
250
251 if (r->ooreplyCnt > 0)
252 {
253 out->datalen = r->ooreplyCnt;
254 out->databuf = malloc(r->ooreplyCnt);
255 if (out->databuf == NULL)
256 {
257 free(out);
258 *reply = NULL;
259 vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
260 return KERN_FAILURE;
261 }
262
263 memcpy(out->databuf, (char *)r->ooreply, r->ooreplyCnt);
264 vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
265 }
266 else if (r->replyCnt > 0)
267 {
268 out->datalen = r->replyCnt;
269 out->databuf = malloc(r->replyCnt);
270 if (out->databuf == NULL)
271 {
272 free(out);
273 *reply = NULL;
274 return KERN_FAILURE;
275 }
276
277 memcpy(out->databuf, r->reply, r->replyCnt);
278 }
279
280 *reply = kvbuf_decode(out);
281 if (*reply == NULL)
282 {
283 /* DS returned no data */
284 free(out->databuf);
285 free(out);
286 }
287
288 _LI_free_request(r);
289
290 return KERN_SUCCESS;
291 }
292
293 static void
294 _LI_worklist_append(_li_async_request_t *r)
295 {
296 _li_async_request_t *p;
297
298 if (r == NULL) return;
299
300 pthread_mutex_lock(&_li_worklist_lock);
301
302 if (_li_worklist == NULL)
303 {
304 _li_worklist = r;
305 pthread_mutex_unlock(&_li_worklist_lock);
306 return;
307 }
308
309 for (p = _li_worklist; p->next != NULL; p = p->next);
310 p->next = r;
311
312 pthread_mutex_unlock(&_li_worklist_lock);
313 }
314
315 void
316 LI_async_call_cancel(mach_port_t p, void **context)
317 {
318 _li_async_request_t *req;
319
320 req = _LI_worklist_remove(p);
321
322 if (req != NULL)
323 {
324 if (context != NULL) *context = req->context;
325 _LI_free_request(req);
326 }
327 else if (p != MACH_PORT_NULL)
328 {
329 mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1);
330 }
331 }
332
333 void
334 lu_async_call_cancel(mach_port_t p)
335 {
336 LI_async_call_cancel(p, NULL);
337 }
338
339 static _li_async_request_t *
340 _LI_create_request(uint32_t proc, kvbuf_t *query, void *callback, void *context)
341 {
342 _li_async_request_t *r;
343 kern_return_t status;
344 mach_port_t target;
345
346 if (_ds_running() == 0) return NULL;
347 if (query == NULL) return NULL;
348 if (query->datalen > MAX_MIG_INLINE_DATA) return NULL;
349
350 r = (_li_async_request_t *)calloc(1, sizeof(_li_async_request_t));
351 if (r == NULL) return NULL;
352
353 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(r->reply_port));
354 if (status != KERN_SUCCESS)
355 {
356 _LI_free_request(r);
357 return NULL;
358 }
359
360 target = MACH_PORT_NULL;
361
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);
364
365 r->retry = MAX_LOOKUP_ATTEMPTS;
366
367 r->context = context;
368 r->callback = callback;
369 r->proc = proc;
370
371 memcpy(r->request, query->databuf, query->datalen);
372 r->requestCnt = query->datalen;
373
374 r->next = NULL;
375
376 return r;
377 }
378
379 kern_return_t
380 LI_async_start(mach_port_t *p, uint32_t proc, kvbuf_t *query, void *callback, void *context)
381 {
382 _li_async_request_t *r;
383 kern_return_t status;
384 uint32_t retry;
385
386 if (p == NULL) return KERN_FAILURE;
387
388 *p = MACH_PORT_NULL;
389
390 if (_ds_running() == 0) return KERN_FAILURE;
391 if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
392
393 /* Make a request struct to keep track */
394 r = _LI_create_request(proc, query, callback, context);
395 if (r == NULL) return KERN_FAILURE;
396
397 status = MIG_SERVER_DIED;
398 for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
399 {
400 status = _LI_async_send(r);
401 }
402
403 if (status != KERN_SUCCESS)
404 {
405 _LI_free_request(r);
406 return status;
407 }
408
409 /* Add request to worklist */
410 _LI_worklist_append(r);
411
412 *p = r->reply_port;
413
414 return KERN_SUCCESS;
415 }
416
417 kern_return_t
418 LI_async_send(mach_port_t *p, uint32_t proc, kvbuf_t *query)
419 {
420 return LI_async_start(p, proc, query, NULL, NULL);
421 }
422
423 kern_return_t
424 LI_async_handle_reply(mach_msg_header_t *msg, kvarray_t **reply, void **callback, void **context)
425 {
426 _li_async_request_t *req;
427 kvbuf_t *out;
428 kern_return_t status;
429 uint32_t retry;
430 mig_reply_error_t *bufReply;
431
432 if (msg == NULL) return -1;
433
434 /* If reply status was an error, resend */
435 if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS)
436 {
437 /* if server died */
438 req = _LI_worklist_find(msg->msgh_local_port);
439 if (req == NULL) return -1;
440
441 status = MIG_SERVER_DIED;
442 for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
443 {
444 /* send message */
445 status = _LI_async_send(req);
446 }
447
448 if (status != KERN_SUCCESS) return -1;
449
450 return MIG_REPLY_MISMATCH;
451 }
452
453 /* need to implement the msg_server_once type code here */
454 mach_msg_size_t reply_alloc = round_page(65536 + MAX_TRAILER_SIZE);
455
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;
458
459 status = DSlibinfoMIGAsyncReply_server(msg, (mach_msg_header_t *)bufReply);
460
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);
463
464 vm_deallocate(mach_task_self(), (vm_address_t) bufReply, reply_alloc);
465
466 if (status == FALSE) return KERN_FAILURE;
467
468 req = _LI_worklist_remove(msg->msgh_local_port);
469 if (req == NULL) return KERN_FAILURE;
470
471 *callback = req->callback;
472 *context = req->context;
473
474 out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
475 if (out == NULL)
476 {
477 if (req->ooreplyCnt > 0) vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
478 return KERN_FAILURE;
479 }
480
481 if (req->ooreplyCnt > 0)
482 {
483 out->datalen = req->ooreplyCnt;
484 out->databuf = malloc(req->ooreplyCnt);
485 if (out->databuf == NULL)
486 {
487 free(out);
488 *reply = NULL;
489 vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
490 return KERN_FAILURE;
491 }
492
493 memcpy(out->databuf, (char *)req->ooreply, req->ooreplyCnt);
494 vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
495 }
496 else if (req->replyCnt > 0)
497 {
498 out->datalen = req->replyCnt;
499 out->databuf = malloc(req->replyCnt);
500 if (out->databuf == NULL)
501 {
502 free(out);
503 *reply = NULL;
504 return KERN_FAILURE;
505 }
506
507 memcpy(out->databuf, req->reply, req->replyCnt);
508 }
509
510 *reply = kvbuf_decode(out);
511 if (*reply == NULL)
512 {
513 /* DS returned no data */
514 free(out->databuf);
515 free(out);
516 }
517
518 _LI_free_request(req);
519
520 return KERN_SUCCESS;
521 }
522
523 static void
524 _LI_thread_info_free(void *x)
525 {
526 struct li_thread_info *tdata;
527
528 if (x == NULL) return;
529
530 tdata = (struct li_thread_info *)x;
531 LI_ils_free(tdata->li_entry, tdata->li_entry_size);
532 LI_data_free_kvarray(tdata);
533
534 free(tdata);
535 }
536
537 static void
538 _LI_data_free(void *x)
539 {
540 struct _li_data_s *t;
541 int i;
542
543 if (x == NULL) return;
544
545 t = (struct _li_data_s *)x;
546
547 for (i = 0; i < t->icount; i++)
548 {
549 _LI_thread_info_free(t->idata[i]);
550 t->idata[i] = NULL;
551 }
552
553 if (t->ikey != NULL) free(t->ikey);
554 t->ikey = NULL;
555
556 if (t->idata != NULL) free(t->idata);
557 t->idata = NULL;
558
559 free(t);
560 }
561
562 static void
563 _LI_data_init()
564 {
565 pthread_key_create(&_info_key, _LI_data_free);
566 return;
567 }
568
569 static struct _li_data_s *
570 _LI_data_get()
571 {
572 struct _li_data_s *libinfo_data;
573
574 /*
575 * Only one thread should create the _info_key
576 */
577 pthread_once(&_info_key_initialized, _LI_data_init);
578
579 /* Check if this thread already created libinfo_data */
580 libinfo_data = pthread_getspecific(_info_key);
581 if (libinfo_data != NULL) return libinfo_data;
582
583 libinfo_data = (struct _li_data_s *)calloc(1, sizeof(struct _li_data_s));
584 if (libinfo_data == NULL) return NULL;
585
586 pthread_setspecific(_info_key, libinfo_data);
587 return libinfo_data;
588 }
589
590 __private_extern__ void *
591 LI_data_find_key(uint32_t key)
592 {
593 struct _li_data_s *libinfo_data;
594 uint32_t i;
595
596 libinfo_data = _LI_data_get();
597 if (libinfo_data == NULL) return NULL;
598
599 for (i = 0; i < libinfo_data->icount; i++)
600 {
601 if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
602 }
603
604 return NULL;
605 }
606
607 __private_extern__ void *
608 LI_data_create_key(uint32_t key, size_t esize)
609 {
610 struct _li_data_s *libinfo_data;
611 struct li_thread_info *tdata;
612 uint32_t i, n;
613
614 libinfo_data = _LI_data_get();
615 if (libinfo_data == NULL) return NULL;
616
617 for (i = 0; i < libinfo_data->icount; i++)
618 {
619 if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
620 }
621
622 i = libinfo_data->icount;
623 n = i + 1;
624
625 if (i == 0)
626 {
627 libinfo_data->ikey = (uint32_t *)malloc(sizeof(uint32_t));
628 libinfo_data->idata = (void **)malloc(sizeof(void *));
629 }
630 else
631 {
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 *));
634 }
635
636 if ((libinfo_data->ikey == NULL) || (libinfo_data->idata == NULL))
637 {
638 if (libinfo_data->ikey != NULL) free(libinfo_data->ikey);
639 libinfo_data->ikey = NULL;
640
641 if (libinfo_data->idata != NULL) free(libinfo_data->idata);
642 libinfo_data->idata = NULL;
643
644 return NULL;
645 }
646
647 tdata = (struct li_thread_info *)calloc(1, sizeof(struct li_thread_info));
648 if (tdata == NULL) return NULL;
649
650 tdata->li_entry_size = esize;
651
652 libinfo_data->ikey[i] = key;
653 libinfo_data->idata[i] = tdata;
654 libinfo_data->icount++;
655
656 return tdata;
657 }
658
659 static uint32_t
660 _LI_data_index(uint32_t key, struct _li_data_s *libinfo_data)
661 {
662 uint32_t i;
663
664 if (libinfo_data == NULL) return (uint32_t)-1;
665
666 for (i = 0; i < libinfo_data->icount; i++)
667 {
668 if (libinfo_data->ikey[i] == key) return i;
669 }
670
671 return (uint32_t)-1;
672 }
673
674 void
675 _LI_data_set_key(uint32_t key, void *data)
676 {
677 struct _li_data_s *libinfo_data;
678 uint32_t i;
679
680 libinfo_data = _LI_data_get();
681 if (libinfo_data == NULL) return;
682
683 i = _LI_data_index(key, libinfo_data);
684 if (i == (uint32_t)-1) return;
685
686 libinfo_data->idata[i] = data;
687 }
688
689 void *
690 _LI_data_get_key(uint32_t key)
691 {
692 struct _li_data_s *libinfo_data;
693 uint32_t i;
694
695 libinfo_data = _LI_data_get();
696 if (libinfo_data == NULL) return NULL;
697
698 i = _LI_data_index(key, libinfo_data);
699 if (i == (uint32_t)-1) return NULL;
700
701 return libinfo_data->idata[i];
702 }
703
704 __private_extern__ void
705 LI_data_free_kvarray(struct li_thread_info *tdata)
706 {
707 if (tdata == NULL) return;
708 if (tdata->li_vm == NULL) return;
709
710 kvarray_free((kvarray_t *)tdata->li_vm);
711 tdata->li_vm = NULL;
712 }
713
714 __private_extern__ void
715 LI_data_recycle(struct li_thread_info *tdata, void *entry, size_t entrysize)
716 {
717 if (tdata == NULL) return;
718
719 LI_ils_free(tdata->li_entry, entrysize);
720 tdata->li_entry = entry;
721 }
722
723 #define KVBUF_CHUNK 256
724
725 /*
726 * kvbuf_t is a list of key/value dictionaries.
727 *
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
732 *
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.
737 *
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.
742 *
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.
747 *
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.
752 *
753 * The cache_entry_list_to_kvbuf() routine contains the only
754 * code that builds an array.
755 *
756 */
757
758 /*
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.
764 */
765 __private_extern__ kvbuf_t *
766 kvbuf_query(char *fmt, ...)
767 {
768 va_list ap;
769 char *arg, *f, str[32];
770 int32_t iarg;
771 uint32_t uarg;
772 kvbuf_t *kv;
773
774 if (fmt == NULL) return NULL;
775
776 kv = kvbuf_new();
777 if (kv == NULL) return NULL;
778
779 kvbuf_add_dict(kv);
780
781 va_start(ap, fmt);
782 for (f = fmt; (*f) != '\0'; f++)
783 {
784 if (*f == 'k')
785 {
786 arg = va_arg(ap, char *);
787 kvbuf_add_key(kv, arg);
788 }
789 else if (*f == 's')
790 {
791 arg = va_arg(ap, char *);
792 kvbuf_add_val(kv, arg);
793 }
794 else if (*f == 'i')
795 {
796 iarg = va_arg(ap, int32_t);
797 snprintf(str, sizeof(str), "%d", iarg);
798 kvbuf_add_val(kv, str);
799 }
800 else if (*f == 'u')
801 {
802 uarg = va_arg(ap,uint32_t);
803 snprintf(str, sizeof(str), "%u", uarg);
804 kvbuf_add_val(kv, str);
805 }
806 }
807 va_end(ap);
808
809 return kv;
810 }
811
812 __private_extern__ kvbuf_t *
813 kvbuf_query_key_val(const char *key, const char *val)
814 {
815 kvbuf_t *kv;
816 uint32_t x, kl, vl, vc;
817 char *p;
818
819 if (key == NULL) return NULL;
820
821 kl = strlen(key) + 1;
822
823 vl = 0;
824 vc = 0;
825
826 if (val != NULL)
827 {
828 vl = strlen(val) + 1;
829 vc = 1;
830 }
831
832 kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
833 if (kv == NULL) return NULL;
834
835 kv->_size = (5 * sizeof(uint32_t)) + kl + vl;
836 kv->datalen = kv->_size;
837
838 kv->databuf = calloc(1, kv->_size);
839 if (kv->databuf == NULL)
840 {
841 free(kv);
842 return NULL;
843 }
844
845 p = kv->databuf;
846
847 /* 1 dict */
848 x = htonl(1);
849 memcpy(p, &x, sizeof(uint32_t));
850 p += sizeof(uint32_t);
851
852 /* 1 key */
853 memcpy(p, &x, sizeof(uint32_t));
854 p += sizeof(uint32_t);
855
856 /* key length */
857 x = htonl(kl);
858 memcpy(p, &x, sizeof(uint32_t));
859 p += sizeof(uint32_t);
860
861 /* key */
862 memcpy(p, key, kl);
863 p += kl;
864
865 /* number of values */
866 x = htonl(vc);
867 memcpy(p, &x, sizeof(uint32_t));
868 p += sizeof(uint32_t);
869
870 if (vc > 0)
871 {
872 /* value length */
873 x = htonl(vl);
874 memcpy(p, &x, sizeof(uint32_t));
875 p += sizeof(uint32_t);
876
877 /* value */
878 memcpy(p, val, vl);
879 }
880
881 return kv;
882 }
883
884 __private_extern__ kvbuf_t *
885 kvbuf_query_key_int(const char *key, int32_t i)
886 {
887 char str[32];
888
889 snprintf(str, sizeof(str), "%d", i);
890 return kvbuf_query_key_val(key, str);
891 }
892
893 __private_extern__ kvbuf_t *
894 kvbuf_query_key_uint(const char *key, uint32_t u)
895 {
896 char str[32];
897
898 snprintf(str, sizeof(str), "%u", u);
899 return kvbuf_query_key_val(key, str);
900 }
901
902 kvbuf_t *
903 kvbuf_new(void)
904 {
905 kvbuf_t *kv;
906
907 kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
908 if (kv == NULL) return NULL;
909
910 kv->_size = KVBUF_START_SIZE;
911 kv->databuf = calloc(1, kv->_size);
912 if (kv->databuf == NULL)
913 {
914 free(kv);
915 return NULL;
916 }
917
918 kv->datalen = sizeof(uint32_t);
919 kv->_dict = kv->datalen;
920
921 return kv;
922 }
923
924 kvbuf_t *
925 kvbuf_init(char *buffer, uint32_t length)
926 {
927 kvbuf_t *kv;
928
929 kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
930 if (kv == NULL) return NULL;
931
932 kv->_size = length;
933 kv->datalen = length;
934 kv->databuf = calloc(1, length);
935 if (kv->databuf == NULL)
936 {
937 free(kv);
938 kv = NULL;
939 }
940 else
941 {
942 memcpy(kv->databuf, buffer, length);
943 }
944
945 return kv;
946 }
947
948 static void
949 kvbuf_grow(kvbuf_t *kv, uint32_t delta)
950 {
951 uint32_t newlen, n;
952 char *p;
953
954 if (kv == NULL) return;
955 if (delta == 0) return;
956
957 if (kv->databuf == NULL) delta += sizeof(uint32_t);
958
959 n = (delta + KVBUF_CHUNK - 1) / KVBUF_CHUNK;
960 newlen = kv->datalen + (n * KVBUF_CHUNK);
961
962 if (newlen <= kv->_size) return;
963
964 kv->_size = newlen;
965
966 if (kv->databuf == NULL)
967 {
968 kv->databuf = calloc(1, kv->_size);
969 if (kv->databuf == NULL)
970 {
971 memset(kv, 0, sizeof(kvbuf_t));
972 return;
973 }
974
975 kv->datalen = sizeof(uint32_t);
976 kv->_dict = sizeof(uint32_t);
977 }
978 else
979 {
980 kv->databuf = reallocf(kv->databuf, kv->_size);
981 if (kv->databuf == NULL)
982 {
983 memset(kv, 0, sizeof(kvbuf_t));
984 return;
985 }
986
987 p = kv->databuf + kv->datalen;
988 memset(p, 0, kv->_size - kv->datalen);
989 }
990 }
991
992 void
993 kvbuf_add_dict(kvbuf_t *kv)
994 {
995 char *p;
996 uint32_t x, dict_count;
997
998 if (kv == NULL) return;
999
1000 /* Add a key count */
1001 kvbuf_grow(kv, sizeof(uint32_t));
1002 if (kv->databuf == NULL) return;
1003
1004 kv->_dict = kv->datalen;
1005 kv->datalen += sizeof(uint32_t);
1006
1007 kv->_key = kv->datalen;
1008 kv->_vlist = 0;
1009 kv->_val = 0;
1010
1011 /* increment and rewrite the dict count */
1012 p = kv->databuf;
1013
1014 x = 0;
1015 memcpy(&x, p, sizeof(uint32_t));
1016 dict_count = ntohl(x);
1017
1018 dict_count++;
1019 x = htonl(dict_count);
1020 memcpy(p, &x, sizeof(uint32_t));
1021 }
1022
1023 void
1024 kvbuf_add_key(kvbuf_t *kv, const char *key)
1025 {
1026 uint32_t kl, x, key_count, delta;
1027 char *p;
1028
1029 if (kv == NULL) return;
1030 if (key == NULL) return;
1031
1032 kl = strlen(key) + 1;
1033
1034 /* Grow to hold key len, key, and value list count. */
1035 delta = (2 * sizeof(uint32_t)) + kl;
1036 kvbuf_grow(kv, delta);
1037
1038 if (kv->databuf == NULL) return;
1039
1040 /* increment and rewrite the key count for the current dictionary */
1041 p = kv->databuf + kv->_dict;
1042
1043 x = 0;
1044 memcpy(&x, p, sizeof(uint32_t));
1045 key_count = ntohl(x);
1046
1047 if (key_count == 0) kv->_key = kv->_dict + sizeof(uint32_t);
1048 else kv->_key = kv->datalen;
1049
1050 key_count++;
1051 x = htonl(key_count);
1052 memcpy(p, &x, sizeof(uint32_t));
1053
1054 /* append key to data buffer */
1055 p = kv->databuf + kv->datalen;
1056
1057 x = htonl(kl);
1058 memcpy(p, &x, sizeof(uint32_t));
1059 p += sizeof(uint32_t);
1060 memcpy(p, key, kl);
1061 p += kl;
1062
1063 kv->_vlist = kv->datalen + sizeof(uint32_t) + kl;
1064
1065 x = 0;
1066 memcpy(p, &x, sizeof(uint32_t));
1067
1068 kv->datalen += delta;
1069 kv->_val = kv->datalen;
1070 }
1071
1072 void
1073 kvbuf_add_val_len(kvbuf_t *kv, const char *val, uint32_t len)
1074 {
1075 uint32_t x, val_count, delta;
1076 char *p;
1077
1078 if (kv == NULL) return;
1079 if (val == NULL) return;
1080 if (len == 0) return;
1081
1082 /* Grow to hold val len and value. */
1083 delta = sizeof(uint32_t) + len;
1084 kvbuf_grow(kv, delta);
1085
1086 if (kv->databuf == NULL) return;
1087
1088 /* increment and rewrite the value count for the value_list dictionary */
1089 p = kv->databuf + kv->_vlist;
1090
1091 x = 0;
1092 memcpy(&x, p, sizeof(uint32_t));
1093 val_count = ntohl(x);
1094 val_count++;
1095 x = htonl(val_count);
1096 memcpy(p, &x, sizeof(uint32_t));
1097
1098 /* append val to data buffer */
1099 p = kv->databuf + kv->_val;
1100
1101 x = htonl(len);
1102 memcpy(p, &x, sizeof(uint32_t));
1103 p += sizeof(uint32_t);
1104 memcpy(p, val, len);
1105 p += len;
1106
1107 kv->datalen += delta;
1108 kv->_val = kv->datalen;
1109 }
1110
1111 /*
1112 * WARNING! Kludge Alert!
1113 *
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.
1117 */
1118 uint32_t
1119 kvbuf_get_len(const char *p)
1120 {
1121 uint32_t x;
1122
1123 x = 0;
1124 memcpy(&x, p - sizeof(uint32_t), sizeof(uint32_t));
1125 return ntohl(x);
1126 }
1127
1128 void
1129 kvbuf_add_val(kvbuf_t *kv, const char *val)
1130 {
1131 if (kv == NULL) return;
1132 if (val == NULL) return;
1133
1134 kvbuf_add_val_len(kv, val, strlen(val) + 1);
1135 }
1136
1137 void
1138 kvbuf_free(kvbuf_t *kv)
1139 {
1140 if (kv == NULL) return;
1141 if (kv->databuf != NULL) free(kv->databuf);
1142 memset(kv, 0, sizeof(kvbuf_t));
1143 free(kv);
1144 }
1145
1146 /* appends a kvbuf to an existing kvbuf */
1147 void
1148 kvbuf_append_kvbuf(kvbuf_t *kv, const kvbuf_t *kv2)
1149 {
1150 uint32_t curr_count, new_count, temp;
1151
1152 if (kv == NULL) return;
1153 if (kv2 == NULL) return;
1154
1155 curr_count = 0;
1156 new_count = 0;
1157
1158 memcpy(&temp, kv->databuf, sizeof(uint32_t));
1159 curr_count = ntohl(temp);
1160
1161 memcpy(&temp, kv2->databuf, sizeof(uint32_t));
1162 new_count = ntohl(temp);
1163
1164 /* nothing to do */
1165 if (new_count == 0) return;
1166
1167 /* add the dictionary count to the current dictionary counts */
1168 curr_count += new_count;
1169
1170 temp = htonl(curr_count);
1171 memcpy(kv->databuf, &temp, sizeof(uint32_t));
1172
1173 /* grow the current buffer so we can append the new buffer */
1174 temp = kv2->datalen - sizeof(uint32_t);
1175
1176 kvbuf_grow(kv, temp);
1177
1178 memcpy(kv->databuf + kv->datalen, kv2->databuf + sizeof(uint32_t), temp);
1179 kv->datalen += temp;
1180 }
1181
1182 /* returns number of dictionaries */
1183 uint32_t
1184 kvbuf_reset(kvbuf_t *kv)
1185 {
1186 uint32_t x;
1187
1188 if (kv == NULL) return 0;
1189 if (kv->databuf == NULL) return 0;
1190
1191 kv->_dict = 0;
1192 kv->_key = 0;
1193 kv->_vlist = 0;
1194 kv->_val = 0;
1195
1196 if (kv->datalen < sizeof(uint32_t)) return 0;
1197
1198 x = 0;
1199 memcpy(&x, kv->databuf, sizeof(uint32_t));
1200 return ntohl(x);
1201 }
1202
1203 /* advance to next dictionary, returns key count */
1204 uint32_t
1205 kvbuf_next_dict(kvbuf_t *kv)
1206 {
1207 uint32_t x, k, v, kcount, vcount, kl, vl;
1208 char *p;
1209
1210 if (kv == NULL) return 0;
1211 if (kv->databuf == NULL) return 0;
1212
1213 kv->_key = 0;
1214 kv->_vlist = 0;
1215 kv->_val = 0;
1216
1217 if (kv->_dict == 0)
1218 {
1219 /* first dict */
1220 if (kv->datalen < sizeof(uint32_t)) return 0;
1221 kv->_dict = sizeof(uint32_t);
1222
1223 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
1224
1225 p = kv->databuf + kv->_dict;
1226 x = 0;
1227 memcpy(&x, p, sizeof(uint32_t));
1228 kcount = ntohl(x);
1229
1230 return kcount;
1231 }
1232
1233 p = kv->databuf + kv->_dict;
1234
1235 x = 0;
1236 memcpy(&x, p, sizeof(uint32_t));
1237 p += sizeof(uint32_t);
1238 kv->_dict += sizeof(uint32_t);
1239 kcount = ntohl(x);
1240
1241 for (k = 0; k < kcount; k++)
1242 {
1243 x = 0;
1244 memcpy(&x, p, sizeof(uint32_t));
1245 p += sizeof(uint32_t);
1246 kv->_dict += sizeof(uint32_t);
1247 kl = ntohl(x);
1248 p += kl;
1249 kv->_dict += kl;
1250
1251 x = 0;
1252 memcpy(&x, p, sizeof(uint32_t));
1253 p += sizeof(uint32_t);
1254 kv->_dict += sizeof(uint32_t);
1255 vcount = ntohl(x);
1256
1257 for (v = 0; v < vcount; v++)
1258 {
1259 x = 0;
1260 memcpy(&x, p, sizeof(uint32_t));
1261 p += sizeof(uint32_t);
1262 kv->_dict += sizeof(uint32_t);
1263 vl = ntohl(x);
1264 p += vl;
1265 kv->_dict += vl;
1266 }
1267 }
1268
1269 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
1270
1271 p = kv->databuf + kv->_dict;
1272 x = 0;
1273 memcpy(&x, p, sizeof(uint32_t));
1274 kcount = ntohl(x);
1275
1276 return kcount;
1277 }
1278
1279 /* advance to next key, returns key and sets val_count */
1280 char *
1281 kvbuf_next_key(kvbuf_t *kv, uint32_t *val_count)
1282 {
1283 uint32_t x, kl, v, vl, vc;
1284 char *p, *out;
1285
1286 if (kv == NULL) return NULL;
1287 if (val_count == NULL) return NULL;
1288
1289 *val_count = 0;
1290
1291 if (kv->databuf == NULL) return NULL;
1292 if (kv->_dict == 0) return NULL;
1293
1294 kv->_vlist = 0;
1295 kv->_val = 0;
1296
1297 if (kv->_key == 0)
1298 {
1299 /* first key */
1300 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return NULL;
1301 kv->_key = kv->_dict + sizeof(uint32_t);
1302 }
1303 else
1304 {
1305 p = kv->databuf + kv->_key;
1306
1307 x = 0;
1308 memcpy(&x, p, sizeof(uint32_t));
1309 kl = ntohl(x);
1310
1311 if (kv->datalen < (kv->_key + sizeof(uint32_t) + kl)) return NULL;
1312
1313 p += (sizeof(uint32_t) + kl);
1314 kv->_key += (sizeof(uint32_t) + kl);
1315
1316 /* skip over values */
1317 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
1318
1319 x = 0;
1320 memcpy(&x, p, sizeof(uint32_t));
1321 vc = ntohl(x);
1322
1323 p += sizeof(uint32_t);
1324 kv->_key += sizeof(uint32_t);
1325
1326 for (v = 0; v < vc; v++)
1327 {
1328 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
1329
1330 x = 0;
1331 memcpy(&x, p, sizeof(uint32_t));
1332 vl = ntohl(x);
1333
1334 if (kv->datalen < (kv->_key + kl)) return NULL;
1335
1336 p += (sizeof(uint32_t) + vl);
1337 kv->_key += (sizeof(uint32_t) + vl);
1338 }
1339 }
1340
1341 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
1342
1343 p = kv->databuf + kv->_key;
1344 x = 0;
1345 memcpy(&x, p, sizeof(uint32_t));
1346 kl = ntohl(x);
1347
1348 p += sizeof(uint32_t);
1349 out = p;
1350
1351 kv->_vlist = kv->_key + sizeof(uint32_t) + kl;
1352 if (kv->datalen < (kv->_vlist + sizeof(uint32_t)))
1353 {
1354 kv->_vlist = 0;
1355 return NULL;
1356 }
1357
1358 p = kv->databuf + kv->_vlist;
1359 x = 0;
1360 memcpy(&x, p, sizeof(uint32_t));
1361 *val_count = ntohl(x);
1362
1363 return out;
1364 }
1365
1366 char *
1367 kvbuf_next_val(kvbuf_t *kv)
1368 {
1369 return kvbuf_next_val_len(kv, NULL);
1370 }
1371
1372 char *
1373 kvbuf_next_val_len(kvbuf_t *kv, uint32_t *len)
1374 {
1375 uint32_t x = 0;
1376 uint32_t vltemp = 0;
1377 char *p;
1378
1379 if (kv == NULL) return NULL;
1380 if (kv->databuf == NULL) return NULL;
1381 if (kv->_vlist == 0) return NULL;
1382
1383 if (kv->_val == 0)
1384 {
1385 /* first val */
1386 if (kv->datalen < (kv->_vlist + sizeof(uint32_t))) return NULL;
1387 kv->_val = kv->_vlist + sizeof(uint32_t);
1388
1389 p = kv->databuf + kv->_val;
1390
1391 memcpy(&x, p, sizeof(uint32_t));
1392 vltemp = ntohl(x);
1393 }
1394 else
1395 {
1396 p = kv->databuf + kv->_val;
1397
1398 memcpy(&x, p, sizeof(uint32_t));
1399 vltemp = ntohl(x);
1400
1401 if (kv->datalen < (kv->_val + sizeof(uint32_t) + vltemp)) return NULL;
1402
1403 p += (sizeof(uint32_t) + vltemp);
1404 kv->_val += (sizeof(uint32_t) + vltemp);
1405 }
1406
1407 if (kv->datalen < (kv->_val + sizeof(uint32_t))) return NULL;
1408
1409 if (len != NULL) (*len) = vltemp;
1410 p = kv->databuf + kv->_val + sizeof(uint32_t);
1411 return p;
1412 }
1413
1414 /*
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.
1420 *
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().
1424 */
1425 kvarray_t *
1426 kvbuf_decode(kvbuf_t *kv)
1427 {
1428 kvarray_t *a;
1429 uint32_t x, d, k, v;
1430 char *p;
1431
1432 if (kv == NULL) return NULL;
1433 if (kv->databuf == NULL) return NULL;
1434
1435 if (kv->datalen < sizeof(uint32_t)) return NULL;
1436
1437 p = kv->databuf;
1438 kv->_size = kv->datalen;
1439
1440 /* array count */
1441 x = 0;
1442 memcpy(&x, p, sizeof(uint32_t));
1443 p += sizeof(uint32_t);
1444 kv->_size -= sizeof(uint32_t);
1445 x = ntohl(x);
1446
1447 if (x == 0) return NULL;
1448
1449 a = (kvarray_t *)calloc(1, sizeof(kvarray_t));
1450 if (a == NULL) return NULL;
1451
1452 a->count = x;
1453 a->dict = (kvdict_t *)calloc(a->count, sizeof(kvdict_t));
1454 if (a->dict == NULL)
1455 {
1456 free(a);
1457 return NULL;
1458 }
1459
1460 for (d = 0; d < a->count; d++)
1461 {
1462 if (kv->_size < sizeof(uint32_t))
1463 {
1464 kvarray_free(a);
1465 return NULL;
1466 }
1467
1468 /* key count */
1469 x = 0;
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);
1474
1475 if (a->dict[d].kcount > 0)
1476 {
1477 a->dict[d].key = (const char **)calloc(a->dict[d].kcount, sizeof(const char *));
1478 if (a->dict[d].key == NULL)
1479 {
1480 kvarray_free(a);
1481 return NULL;
1482 }
1483
1484 a->dict[d].vcount = (uint32_t *)calloc(a->dict[d].kcount, sizeof(uint32_t));
1485 if (a->dict[d].vcount == NULL)
1486 {
1487 kvarray_free(a);
1488 return NULL;
1489 }
1490
1491 a->dict[d].val = (const char ***)calloc(a->dict[d].kcount, sizeof(char **));
1492 if (a->dict[d].val == NULL)
1493 {
1494 kvarray_free(a);
1495 return NULL;
1496 }
1497 }
1498
1499 for (k = 0; k < a->dict[d].kcount; k++)
1500 {
1501 /* get key */
1502 if (kv->_size < sizeof(uint32_t))
1503 {
1504 kvarray_free(a);
1505 return NULL;
1506 }
1507
1508 /* key length */
1509 x = 0;
1510 memcpy(&x, p, sizeof(uint32_t));
1511 p += sizeof(uint32_t);
1512 kv->_size -= sizeof(uint32_t);
1513 x = ntohl(x);
1514
1515 if (kv->_size < x)
1516 {
1517 kvarray_free(a);
1518 return NULL;
1519 }
1520
1521 /* key data */
1522 a->dict[d].key[k] = p;
1523
1524 p += x;
1525 kv->_size -= x;
1526
1527 if (kv->_size < sizeof(uint32_t))
1528 {
1529 kvarray_free(a);
1530 return NULL;
1531 }
1532
1533 /* val count */
1534 x = 0;
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);
1539
1540 if (a->dict[d].vcount[k] > 0)
1541 {
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)
1545 {
1546 kvarray_free(a);
1547 return NULL;
1548 }
1549 }
1550
1551 for (v = 0; v < a->dict[d].vcount[k]; v++)
1552 {
1553 /* get val */
1554 if (kv->_size < sizeof(uint32_t))
1555 {
1556 kvarray_free(a);
1557 return NULL;
1558 }
1559
1560 /* val length */
1561 x = 0;
1562 memcpy(&x, p, sizeof(uint32_t));
1563 p += sizeof(uint32_t);
1564 kv->_size -= sizeof(uint32_t);
1565 x = ntohl(x);
1566
1567 if (kv->_size < x)
1568 {
1569 kvarray_free(a);
1570 return NULL;
1571 }
1572
1573 /* val data */
1574 a->dict[d].val[k][v] = p;
1575
1576 p += x;
1577 kv->_size -= x;
1578 }
1579 }
1580 }
1581
1582 a->kv = kv;
1583 return a;
1584 }
1585
1586 void
1587 kvarray_free(kvarray_t *a)
1588 {
1589 uint32_t d, k;
1590
1591 if (a == NULL) return;
1592
1593 for (d = 0; d < a->count; d++)
1594 {
1595 for (k = 0; k < a->dict[d].kcount; k++)
1596 {
1597 if (a->dict[d].val == NULL) continue;
1598 if (a->dict[d].val[k] != NULL) free(a->dict[d].val[k]);
1599 }
1600
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);
1604 }
1605
1606 a->count = 0;
1607
1608 if (a->dict != NULL) free(a->dict);
1609 a->dict = NULL;
1610
1611 if (a->kv != NULL) kvbuf_free(a->kv);
1612 a->kv = NULL;
1613
1614 free(a);
1615 }
1616
1617 kern_return_t
1618 LI_DSLookupGetProcedureNumber(const char *name, int32_t *procno)
1619 {
1620 kern_return_t status;
1621 security_token_t token;
1622 uint32_t n, len;
1623
1624 if (name == NULL) return KERN_FAILURE;
1625
1626 len = strlen(name) + 1;
1627 if (len == 1) return KERN_FAILURE;
1628
1629 token.val[0] = -1;
1630 token.val[1] = -1;
1631
1632 if (_ds_running() == 0) return KERN_FAILURE;
1633 if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
1634
1635 status = MIG_SERVER_DIED;
1636 for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1637 {
1638 status = libinfoDSmig_GetProcedureNumber(_ds_port, (char *)name, procno, &token);
1639
1640 if (status == MACH_SEND_INVALID_DEST)
1641 {
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;
1646 }
1647 }
1648
1649 if (status != KERN_SUCCESS)
1650 {
1651 #ifdef DEBUG
1652 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s status %u", name, status);
1653 #endif
1654 return status;
1655 }
1656
1657 if (token.val[0] != 0)
1658 {
1659 #ifdef DEBUG
1660 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s auth failure uid=%d", name, token.val[0]);
1661 #endif
1662 return KERN_FAILURE;
1663 }
1664
1665 #ifdef DEBUG
1666 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s = %d", name, *procno);
1667 #endif
1668 return status;
1669 }
1670
1671 __private_extern__ kern_return_t
1672 LI_DSLookupQuery(int32_t procno, kvbuf_t *request, kvarray_t **reply)
1673 {
1674 kern_return_t status;
1675 security_token_t token;
1676 uint32_t n;
1677 mach_msg_type_number_t illen, oolen;
1678 char ilbuf[MAX_MIG_INLINE_DATA];
1679 vm_offset_t oobuf;
1680 kvbuf_t *out;
1681
1682 if (reply == NULL) return KERN_FAILURE;
1683 if ((request != NULL) && ((request->databuf == NULL) || (request->datalen == 0))) return KERN_FAILURE;
1684
1685 token.val[0] = -1;
1686 token.val[1] = -1;
1687 *reply = NULL;
1688
1689 if (_ds_running() == 0) return KERN_FAILURE;
1690 if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
1691
1692 status = MIG_SERVER_DIED;
1693 for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1694 {
1695 illen = 0;
1696 oolen = 0;
1697 oobuf = 0;
1698
1699 if (request != NULL)
1700 {
1701 status = libinfoDSmig_Query(_ds_port, procno, request->databuf, request->datalen, ilbuf, &illen, &oobuf, &oolen, &token);
1702 }
1703 else
1704 {
1705 status = libinfoDSmig_Query(_ds_port, procno, "", 0, ilbuf, &illen, &oobuf, &oolen, &token);
1706 }
1707
1708 if (status == MACH_SEND_INVALID_DEST)
1709 {
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;
1714 }
1715 }
1716
1717 if (status != KERN_SUCCESS)
1718 {
1719 #ifdef DEBUG
1720 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status %u", procno, status);
1721 #endif
1722 return status;
1723 }
1724
1725 if (token.val[0] != 0)
1726 {
1727 #ifdef DEBUG
1728 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d auth failure uid=%d", procno, token.val[0]);
1729 #endif
1730 if (oolen > 0) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
1731 return KERN_FAILURE;
1732 }
1733
1734 out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
1735 if (out == NULL)
1736 {
1737 if (oolen > 0) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
1738 return KERN_FAILURE;
1739 }
1740
1741 if (oolen > 0)
1742 {
1743 out->datalen = oolen;
1744 out->databuf = malloc(oolen);
1745 if (out->databuf == NULL)
1746 {
1747 free(out);
1748 *reply = NULL;
1749 vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
1750 return KERN_FAILURE;
1751 }
1752
1753 memcpy(out->databuf, (char *)oobuf, oolen);
1754 vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
1755 }
1756 else if (illen > 0)
1757 {
1758 out->datalen = illen;
1759 out->databuf = malloc(illen);
1760 if (out->databuf == NULL)
1761 {
1762 free(out);
1763 *reply = NULL;
1764 return KERN_FAILURE;
1765 }
1766
1767 memcpy(out->databuf, ilbuf, illen);
1768 }
1769
1770 *reply = kvbuf_decode(out);
1771 if (*reply == NULL)
1772 {
1773 /* DS returned no data */
1774 free(out->databuf);
1775 free(out);
1776 }
1777
1778 #ifdef DEBUG
1779 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status OK", procno);
1780 #endif
1781 return status;
1782 }
1783
1784 /*
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.
1788 */
1789 __private_extern__ void *
1790 LI_getent(const char *procname, int *procnum, void *(*extract)(kvarray_t *), int tkey, size_t esize)
1791 {
1792 void *entry;
1793 struct li_thread_info *tdata;
1794 kvarray_t *reply;
1795 kern_return_t status;
1796
1797 tdata = LI_data_create_key(tkey, esize);
1798 if (tdata == NULL) return NULL;
1799
1800 if (tdata->li_vm == NULL)
1801 {
1802 if (*procnum < 0)
1803 {
1804 status = LI_DSLookupGetProcedureNumber(procname, procnum);
1805 if (status != KERN_SUCCESS)
1806 {
1807 LI_data_free_kvarray(tdata);
1808 tdata->li_vm = NULL;
1809 return NULL;
1810 }
1811 }
1812
1813 reply = NULL;
1814 status = LI_DSLookupQuery(*procnum, NULL, &reply);
1815
1816 if (status != KERN_SUCCESS)
1817 {
1818 LI_data_free_kvarray(tdata);
1819 tdata->li_vm = NULL;
1820 return NULL;
1821 }
1822
1823 tdata->li_vm = (char *)reply;
1824 }
1825
1826 entry = extract((kvarray_t *)(tdata->li_vm));
1827 if (entry == NULL)
1828 {
1829 LI_data_free_kvarray(tdata);
1830 tdata->li_vm = NULL;
1831 return NULL;
1832 }
1833
1834 return entry;
1835 }
1836
1837 __private_extern__ void *
1838 LI_getone(const char *procname, int *procnum, void *(*extract)(kvarray_t *), const char *key, const char *val)
1839 {
1840 void *entry;
1841 kvbuf_t *request;
1842 kvarray_t *reply;
1843 kern_return_t status;
1844
1845 if (*procnum < 0)
1846 {
1847 status = LI_DSLookupGetProcedureNumber(procname, procnum);
1848 if (status != KERN_SUCCESS) return NULL;
1849 }
1850
1851 request = kvbuf_query_key_val(key, val);
1852 if (request == NULL) return NULL;
1853
1854 reply = NULL;
1855 status = LI_DSLookupQuery(*procnum, request, &reply);
1856 kvbuf_free(request);
1857
1858 if (status != KERN_SUCCESS) return NULL;
1859
1860 entry = extract(reply);
1861 kvarray_free(reply);
1862
1863 return entry;
1864 }
1865
1866 __private_extern__
1867 int LI_L1_cache_check(int tkey)
1868 {
1869 int check, x;
1870 const char *notify_key;
1871
1872 /* check if L1 cache is disabled */
1873 if (gL1CacheEnabled == 0) return LI_L1_CACHE_DISABLED;
1874
1875 /* Initialize on first call */
1876 if (_L1_notify_token[0] == -1)
1877 {
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);
1881 }
1882
1883 if (_L1_notify_token[0] == -1) return LI_L1_CACHE_FAILED;
1884
1885 check = 1;
1886 if (notify_check(_L1_notify_token[0], &check) != 0) return LI_L1_CACHE_FAILED;
1887 if (check == 1) return LI_L1_CACHE_STALE;
1888
1889 x = 0;
1890 notify_key = NULL;
1891
1892 switch (tkey)
1893 {
1894 case _li_data_key_group:
1895 {
1896 x = 1;
1897 notify_key = L1_CACHE_NOTIFICATION_KEY_GROUP;
1898 break;
1899 }
1900 case _li_data_key_host:
1901 {
1902 x = 2;
1903 notify_key = L1_CACHE_NOTIFICATION_KEY_HOST;
1904 break;
1905 }
1906 case _li_data_key_service:
1907 {
1908 x = 3;
1909 notify_key = L1_CACHE_NOTIFICATION_KEY_SERVICE;
1910 break;
1911 }
1912 case _li_data_key_user:
1913 {
1914 x = 4;
1915 notify_key = L1_CACHE_NOTIFICATION_KEY_USER;
1916 break;
1917 }
1918 default: break;
1919 }
1920
1921 if ((x != 0) && (notify_key != NULL))
1922 {
1923 /* Initialize on first call */
1924 if (_L1_notify_token[x] == -1)
1925 {
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);
1929 }
1930
1931 if (_L1_notify_token[x] == -1) return LI_L1_CACHE_FAILED;
1932
1933 check = 1;
1934 if (notify_check(_L1_notify_token[x], &check) != 0) return LI_L1_CACHE_FAILED;
1935 if (check == 1) return LI_L1_CACHE_STALE;
1936 }
1937
1938 return LI_L1_CACHE_OK;
1939 }
1940
1941 static uint32_t
1942 padsize(size_t curr, size_t item, const uint32_t *align)
1943 {
1944 uint32_t na, diff;
1945
1946 if (item > 8) item = 8;
1947
1948 na = align[item];
1949 if (na == 0) return 0;
1950
1951 diff = curr % na;
1952 if (diff == 0) return 0;
1953
1954 return na - diff;
1955 }
1956
1957
1958 /*
1959 * Create a structure using in-line memory (i.e. all one blob).
1960 * This reduces malloc/free workload.
1961 *
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.
1964 *
1965 * Format keys:
1966 * s NUL terminated string
1967 * 1 1 byte value
1968 * 2 2 byte value
1969 * 4 4 byte value
1970 * 8 8 byte value
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
1976 *
1977 */
1978 __private_extern__ void *
1979 LI_ils_create(char *fmt, ...)
1980 {
1981 va_list ap;
1982 char *arg, *f;
1983 char **list;
1984 void *hp, *dp, *lp, *ils;
1985 uint8_t u8;
1986 uint16_t u16;
1987 uint32_t u32, i, pad;
1988 uint64_t u64;
1989 unsigned long l;
1990 size_t memsize, hsize, csize, slen, largest;
1991 const uint32_t *align;
1992
1993 if (fmt == NULL) return NULL;
1994
1995 largest = 0;
1996 align = align_32;
1997 if (sizeof(char *) == 8) align = align_64;
1998
1999 /* first pass: calculate size */
2000 memsize = ILS_MAGIC_SIZE;
2001 hsize = 0;
2002
2003 va_start(ap, fmt);
2004
2005 for (f = fmt; (*f) != '\0'; f++)
2006 {
2007 csize = 0;
2008 slen = 0;
2009
2010 if (*f == 's')
2011 {
2012 if (largest < sizeof(char *)) largest = sizeof(char *);
2013
2014 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
2015 arg = va_arg(ap, char *);
2016 if (arg != NULL) slen = strlen(arg) + 1;
2017 }
2018 else if (*f == '1')
2019 {
2020 if (largest < 1) largest = 1;
2021
2022 csize = 1;
2023 u8 = va_arg(ap, int);
2024 }
2025 else if (*f == '2')
2026 {
2027 if (largest < 2) largest = 2;
2028
2029 csize = 2 + padsize(hsize, 2, align);
2030 u16 = va_arg(ap, int);
2031 }
2032 else if (*f == '4')
2033 {
2034 if (largest < 4) largest = 4;
2035
2036 csize = 4 + padsize(hsize, 4, align);
2037 u32 = va_arg(ap, uint32_t);
2038 }
2039 else if (*f == '8')
2040 {
2041 if (largest < 8) largest = 8;
2042
2043 csize = 8 + padsize(hsize, 8, align);
2044 u64 = va_arg(ap, uint64_t);
2045 }
2046 else if (*f == 'L')
2047 {
2048 if (largest < sizeof(unsigned long)) largest = sizeof(unsigned long);
2049
2050 csize = sizeof(unsigned long) + padsize(hsize, sizeof(unsigned long), align);
2051 l = va_arg(ap, unsigned long);
2052 }
2053 else if (*f == '*')
2054 {
2055 /* NULL-terminated list of strings */
2056 if (largest < sizeof(char *)) largest = sizeof(char *);
2057
2058 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
2059 list = va_arg(ap, char **);
2060 if (list != NULL)
2061 {
2062 for (i = 0; list[i] != NULL; i++)
2063 {
2064 slen += sizeof(char *);
2065 slen += (strlen(list[i]) + 1);
2066 }
2067
2068 slen += sizeof(char *);
2069 }
2070 }
2071 else if (*f == 'a')
2072 {
2073 /* NULL-terminated list of 4-byte values */
2074 if (largest < sizeof(char *)) largest = sizeof(char *);
2075
2076 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
2077 list = va_arg(ap, char **);
2078 if (list != NULL)
2079 {
2080 for (i = 0; list[i] != NULL; i++)
2081 {
2082 slen += sizeof(char *);
2083 slen += 4;
2084 }
2085
2086 slen += sizeof(char *);
2087 }
2088 }
2089 else if (*f == 'b')
2090 {
2091 /* NULL-terminated list of 8-byte values */
2092 if (largest < sizeof(char *)) largest = sizeof(char *);
2093
2094 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
2095 list = va_arg(ap, char **);
2096 if (list != NULL)
2097 {
2098 for (i = 0; list[i] != NULL; i++)
2099 {
2100 slen += sizeof(char *);
2101 slen += 8;
2102 }
2103
2104 slen += sizeof(char *);
2105 }
2106 }
2107 else if (*f == 'c')
2108 {
2109 /* NULL-terminated list of 16-byte values */
2110 if (largest < sizeof(char *)) largest = sizeof(char *);
2111
2112 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
2113 list = va_arg(ap, char **);
2114 if (list != NULL)
2115 {
2116 for (i = 0; list[i] != NULL; i++)
2117 {
2118 slen += sizeof(char *);
2119 slen += 16;
2120 }
2121
2122 slen += sizeof(char *);
2123 }
2124 }
2125 else return NULL;
2126
2127 memsize += csize;
2128 memsize += slen;
2129 hsize += csize;
2130 }
2131
2132 va_end(ap);
2133
2134 pad = padsize(hsize, largest, align);
2135 memsize += pad;
2136 hsize += pad;
2137
2138 ils = malloc(memsize);
2139 if (ils == NULL)
2140 {
2141 errno = ENOMEM;
2142 return NULL;
2143 }
2144
2145 /* insert magic cookie */
2146 dp = ils + hsize;
2147 memcpy(dp, ILS_MAGIC, ILS_MAGIC_SIZE);
2148 dp += ILS_MAGIC_SIZE;
2149
2150 hp = ils;
2151 hsize = 0;
2152
2153 /* second pass: copy data */
2154 va_start(ap, fmt);
2155 for (f = fmt; (*f) != '\0'; f++)
2156 {
2157 if (*f == 's')
2158 {
2159 pad = padsize(hsize, sizeof(char *), align);
2160 if (pad != 0)
2161 {
2162 memset(hp, 0, pad);
2163 hp += pad;
2164 hsize += pad;
2165 }
2166
2167 arg = va_arg(ap, char *);
2168 if (arg == NULL)
2169 {
2170 memset(hp, 0, sizeof(char *));
2171 }
2172 else
2173 {
2174 memcpy(hp, &dp, sizeof(char *));
2175 slen = strlen(arg) + 1;
2176 memcpy(dp, arg, slen);
2177 dp += slen;
2178 }
2179
2180 hp += sizeof(char *);
2181 hsize += sizeof(char *);
2182 }
2183 else if (*f == '1')
2184 {
2185 u8 = va_arg(ap, int);
2186 memcpy(hp, &u8, sizeof(uint8_t));
2187 hp += sizeof(uint8_t);
2188 }
2189 else if (*f == '2')
2190 {
2191 pad = padsize(hsize, 2, align);
2192 if (pad != 0)
2193 {
2194 memset(hp, 0, pad);
2195 hp += pad;
2196 hsize += pad;
2197 }
2198
2199 u16 = va_arg(ap, int);
2200 memcpy(hp, &u16, sizeof(uint16_t));
2201
2202 hp += sizeof(uint16_t);
2203 hsize += sizeof(uint16_t);
2204 }
2205 else if (*f == '4')
2206 {
2207 pad = padsize(hsize, 4, align);
2208 if (pad != 0)
2209 {
2210 memset(hp, 0, pad);
2211 hp += pad;
2212 hsize += pad;
2213 }
2214
2215 u32 = va_arg(ap, uint32_t);
2216 memcpy(hp, &u32, sizeof(uint32_t));
2217
2218 hp += sizeof(uint32_t);
2219 hsize += sizeof(uint32_t);
2220 }
2221 else if (*f == '8')
2222 {
2223 pad = padsize(hsize, 8, align);
2224 if (pad != 0)
2225 {
2226 memset(hp, 0, pad);
2227 hp += pad;
2228 hsize += pad;
2229 }
2230
2231 u64 = va_arg(ap, uint64_t);
2232 memcpy(hp, &u64, sizeof(uint64_t));
2233
2234 hp += sizeof(uint64_t);
2235 hsize += sizeof(uint64_t);
2236 }
2237 else if (*f == 'L')
2238 {
2239 pad = padsize(hsize, sizeof(unsigned long), align);
2240 if (pad != 0)
2241 {
2242 memset(hp, 0, pad);
2243 hp += pad;
2244 hsize += pad;
2245 }
2246
2247 l = va_arg(ap, unsigned long);
2248 memcpy(hp, &l, sizeof(unsigned long));
2249
2250 hp += sizeof(unsigned long);
2251 hsize += sizeof(unsigned long);
2252 }
2253 else if (*f == '*')
2254 {
2255 pad = padsize(hsize, sizeof(char *), align);
2256 if (pad != 0)
2257 {
2258 memset(hp, 0, pad);
2259 hp += pad;
2260 hsize += pad;
2261 }
2262
2263 list = va_arg(ap, char **);
2264
2265 if (list == NULL)
2266 {
2267 memset(hp, 0, sizeof(char *));
2268 }
2269 else
2270 {
2271 memcpy(hp, &dp, sizeof(char *));
2272
2273 for (i = 0; list[i] != NULL; i++);
2274
2275 lp = dp;
2276 dp += ((i + 1) * sizeof(char *));
2277
2278 for (i = 0; list[i] != NULL; i++)
2279 {
2280 memcpy(lp, &dp, sizeof(char *));
2281 lp += sizeof(char *);
2282 slen = strlen(list[i]) + 1;
2283 memcpy(dp, list[i], slen);
2284 dp += slen;
2285 }
2286
2287 memset(lp, 0, sizeof(char *));
2288 }
2289
2290 hp += sizeof(char *);
2291 hsize += sizeof(char *);
2292 }
2293 else if (*f == 'a')
2294 {
2295 pad = padsize(hsize, sizeof(char *), align);
2296 if (pad != 0)
2297 {
2298 memset(hp, 0, pad);
2299 hp += pad;
2300 hsize += pad;
2301 }
2302
2303 list = va_arg(ap, char **);
2304
2305 if (list == NULL)
2306 {
2307 memset(hp, 0, sizeof(char *));
2308 }
2309 else
2310 {
2311 memcpy(hp, &dp, sizeof(char *));
2312
2313 for (i = 0; list[i] != NULL; i++);
2314
2315 lp = dp;
2316 dp += ((i + 1) * sizeof(char *));
2317
2318 for (i = 0; list[i] != NULL; i++)
2319 {
2320 memcpy(lp, &dp, sizeof(char *));
2321 lp += sizeof(char *);
2322 slen = 4;
2323 memcpy(dp, list[i], slen);
2324 dp += slen;
2325 }
2326
2327 memset(lp, 0, sizeof(char *));
2328 }
2329
2330 hp += sizeof(char *);
2331 hsize += sizeof(char *);
2332 }
2333 else if (*f == 'b')
2334 {
2335 pad = padsize(hsize, sizeof(char *), align);
2336 if (pad != 0)
2337 {
2338 memset(hp, 0, pad);
2339 hp += pad;
2340 hsize += pad;
2341 }
2342
2343 list = va_arg(ap, char **);
2344
2345 if (list == NULL)
2346 {
2347 memset(hp, 0, sizeof(char *));
2348 }
2349 else
2350 {
2351 memcpy(hp, &dp, sizeof(char *));
2352
2353 for (i = 0; list[i] != NULL; i++);
2354
2355 lp = dp;
2356 dp += ((i + 1) * sizeof(char *));
2357
2358 for (i = 0; list[i] != NULL; i++)
2359 {
2360 memcpy(lp, &dp, sizeof(char *));
2361 lp += sizeof(char *);
2362 slen = 8;
2363 memcpy(dp, list[i], slen);
2364 dp += slen;
2365 }
2366
2367 memset(lp, 0, sizeof(char *));
2368 }
2369
2370 hp += sizeof(char *);
2371 hsize += sizeof(char *);
2372 }
2373 else if (*f == 'c')
2374 {
2375 pad = padsize(hsize, sizeof(char *), align);
2376 if (pad != 0)
2377 {
2378 memset(hp, 0, pad);
2379 hp += pad;
2380 hsize += pad;
2381 }
2382
2383 list = va_arg(ap, char **);
2384
2385 if (list == NULL)
2386 {
2387 memset(hp, 0, sizeof(char *));
2388 }
2389 else
2390 {
2391 memcpy(hp, &dp, sizeof(char *));
2392
2393 for (i = 0; list[i] != NULL; i++);
2394
2395 lp = dp;
2396 dp += ((i + 1) * sizeof(char *));
2397
2398 for (i = 0; list[i] != NULL; i++)
2399 {
2400 memcpy(lp, &dp, sizeof(char *));
2401 lp += sizeof(char *);
2402 slen = 16;
2403 memcpy(dp, list[i], slen);
2404 dp += slen;
2405 }
2406
2407 memset(lp, 0, sizeof(char *));
2408 }
2409
2410 hp += sizeof(char *);
2411 hsize += sizeof(char *);
2412 }
2413 }
2414
2415 va_end(ap);
2416
2417 pad = padsize(hsize, largest, align);
2418 if (pad > 0) memset(hp, 0, pad);
2419
2420 return ils;
2421 }
2422
2423 __private_extern__ int
2424 LI_ils_free(void *ils, size_t len)
2425 {
2426 char *p;
2427
2428 if (ils == NULL) return 0;
2429
2430 p = ils + len;
2431 if (memcmp(p, ILS_MAGIC, ILS_MAGIC_SIZE) != 0) return -1;
2432
2433 free(ils);
2434
2435 return 0;
2436 }
2437
2438 kern_return_t
2439 _lookup_link(mach_port_t server, char *name, int *procno)
2440 {
2441 syslog(LOG_ERR, "RED ALERT! lookupd call %s from pid %u", name, getpid());
2442 return KERN_FAILURE;
2443 }
2444
2445 kern_return_t
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)
2447 {
2448 return KERN_FAILURE;
2449 }
2450
2451 kern_return_t
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)
2453 {
2454 return KERN_FAILURE;
2455 }
2456
2457 kern_return_t
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)
2459 {
2460 return KERN_FAILURE;
2461 }