Libinfo-391.tar.gz
[apple/libinfo.git] / lookup.subproj / ils.c
1 /*
2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <mach/mach.h>
28 #include <servers/bootstrap.h>
29 #include <pthread.h>
30 #include <errno.h>
31 #include <notify.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #ifdef DEBUG
35 #include <asl.h>
36 #endif
37 #include <ils.h>
38
39 #define ILS_MAGIC_SIZE 8
40 #define ILS_MAGIC "ILSMAGIC"
41
42 /* GLOBAL */
43
44 static const uint32_t align_32[] = { 0, 1, 2, 0, 4, 0, 0, 0, 4 };
45 static const uint32_t align_64[] = { 0, 1, 2, 0, 4, 0, 0, 0, 8 };
46
47 static uint32_t
48 padsize(size_t curr, size_t item, const uint32_t *align)
49 {
50 uint32_t na, diff;
51
52 if (item > 8) item = 8;
53
54 na = align[item];
55 if (na == 0) return 0;
56
57 diff = curr % na;
58 if (diff == 0) return 0;
59
60 return na - diff;
61 }
62
63 /*
64 * Create a structure using in-line memory (i.e. all one blob).
65 * This reduces malloc/free workload.
66 *
67 * Structure components may be strings, 1, 2, 4, or 8-byte values,
68 * lists of strings, or lists of 4, 8, or 16-byte values.
69 *
70 * Format keys:
71 * s NUL terminated string
72 * 1 1 byte value
73 * 2 2 byte value
74 * 4 4 byte value
75 * 8 8 byte value
76 * S 128 byte value (_SS_MAXSIZE for a sockaddr)
77 * L long (32 or 64 bits, depending on architecture)
78 * m mach_port_t
79 * * NULL-terminated list of strings
80 * a NULL-terminated list of 4-byte values
81 * b NULL-terminated list of 8-byte values
82 * c NULL-terminated list of 16-byte values
83 * @ length (4 bytes) and buffer (requires two parameters)
84 *
85 */
86 void *
87 LI_ils_create(char *fmt, ...)
88 {
89 va_list ap;
90 char *arg, *f;
91 char **list;
92 void *hp, *dp, *lp, *ils;
93 uint8_t u8;
94 uint16_t u16;
95 uint32_t u32, i, pad;
96 uint64_t u64;
97 unsigned long l;
98 mach_port_t m;
99 socket_data_t sdata;
100 size_t memsize, hsize, csize, csizep1, csizep2, slen, largest;
101 const uint32_t *align;
102
103 if (fmt == NULL) return NULL;
104
105 largest = 0;
106 align = align_32;
107 if (sizeof(char *) == 8) align = align_64;
108
109 /* first pass: calculate size */
110 memsize = ILS_MAGIC_SIZE;
111 hsize = 0;
112
113 va_start(ap, fmt);
114
115 for (f = fmt; (*f) != '\0'; f++)
116 {
117 csize = 0;
118 slen = 0;
119
120 switch (*f)
121 {
122 case 's':
123 {
124 if (largest < sizeof(char *)) largest = sizeof(char *);
125
126 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
127 arg = va_arg(ap, char *);
128 if (arg != NULL) slen = strlen(arg) + 1;
129
130 break;
131 }
132
133 case '1':
134 {
135 if (largest < 1) largest = 1;
136
137 csize = 1;
138 u8 = va_arg(ap, int);
139
140 break;
141 }
142
143 case '2':
144 {
145 if (largest < 2) largest = 2;
146
147 csize = 2 + padsize(hsize, 2, align);
148 u16 = va_arg(ap, int);
149
150 break;
151 }
152
153 case '4':
154 {
155 if (largest < 4) largest = 4;
156
157 csize = 4 + padsize(hsize, 4, align);
158 u32 = va_arg(ap, uint32_t);
159
160 break;
161 }
162
163 case '8':
164 {
165 if (largest < 8) largest = 8;
166
167 csize = 8 + padsize(hsize, 8, align);
168 u64 = va_arg(ap, uint64_t);
169
170 break;
171 }
172
173 case 'S':
174 {
175 if (largest < 128) largest = 128;
176
177 /* 4-byte-align since a socket_data_t is really just a buffer */
178 csize = 128 + padsize(hsize, 4, align);
179 sdata = va_arg(ap, socket_data_t);
180
181 break;
182 }
183
184 case 'L':
185 {
186 if (largest < sizeof(unsigned long)) largest = sizeof(unsigned long);
187
188 csize = sizeof(unsigned long) + padsize(hsize, sizeof(unsigned long), align);
189 l = va_arg(ap, unsigned long);
190
191 break;
192 }
193
194 case 'm':
195 {
196 if (largest < sizeof(mach_port_t)) largest = sizeof(mach_port_t);
197
198 csize = sizeof(mach_port_t) + padsize(hsize, sizeof(mach_port_t), align);
199 m = va_arg(ap, mach_port_t);
200
201 break;
202 }
203
204 case '*':
205 {
206 // NULL-terminated list of strings
207 if (largest < sizeof(char *)) largest = sizeof(char *);
208
209 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
210 list = va_arg(ap, char **);
211 if (list != NULL)
212 {
213 for (i = 0; list[i] != NULL; i++)
214 {
215 slen += sizeof(char *);
216 slen += (strlen(list[i]) + 1);
217 }
218 }
219
220 // reserve space for the terminator
221 slen += sizeof(char *);
222
223 break;
224 }
225
226 case 'a':
227 {
228 /* NULL-terminated list of 4-byte values */
229 if (largest < sizeof(char *)) largest = sizeof(char *);
230
231 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
232 list = va_arg(ap, char **);
233 if (list != NULL)
234 {
235 for (i = 0; list[i] != NULL; i++)
236 {
237 slen += sizeof(char *);
238 slen += 4;
239 }
240
241 slen += sizeof(char *);
242 }
243
244 break;
245 }
246
247 case 'b':
248 {
249 /* NULL-terminated list of 8-byte values */
250 if (largest < sizeof(char *)) largest = sizeof(char *);
251
252 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
253 list = va_arg(ap, char **);
254 if (list != NULL)
255 {
256 for (i = 0; list[i] != NULL; i++)
257 {
258 slen += sizeof(char *);
259 slen += 8;
260 }
261
262 slen += sizeof(char *);
263 }
264
265 break;
266 }
267
268 case 'c':
269 {
270 /* NULL-terminated list of 16-byte values */
271 if (largest < sizeof(char *)) largest = sizeof(char *);
272
273 csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
274 list = va_arg(ap, char **);
275 if (list != NULL)
276 {
277 for (i = 0; list[i] != NULL; i++)
278 {
279 slen += sizeof(char *);
280 slen += 16;
281 }
282
283 slen += sizeof(char *);
284 }
285
286 break;
287 }
288
289 case '@':
290 {
291 if (largest < 4) largest = 4;
292 csizep1 = 4 + padsize(hsize, 4, align);
293 slen = va_arg(ap, uint32_t);
294
295 if (largest < sizeof(char *)) largest = sizeof(char *);
296 csizep2 = sizeof(char *) + padsize(hsize + csizep1, sizeof(char *), align);
297 arg = va_arg(ap, char *);
298
299 csize = csizep1 + csizep2;
300
301 break;
302 }
303
304 default: return NULL;
305 }
306
307 memsize += csize;
308 memsize += slen;
309 hsize += csize;
310 }
311
312 va_end(ap);
313
314 pad = padsize(hsize, largest, align);
315 memsize += pad;
316 hsize += pad;
317
318 ils = malloc(memsize);
319 if (ils == NULL)
320 {
321 errno = ENOMEM;
322 return NULL;
323 }
324
325 /* insert magic cookie */
326 dp = ils + hsize;
327 memcpy(dp, ILS_MAGIC, ILS_MAGIC_SIZE);
328 dp += ILS_MAGIC_SIZE;
329
330 hp = ils;
331 hsize = 0;
332
333 /* second pass: copy data */
334 va_start(ap, fmt);
335 for (f = fmt; (*f) != '\0'; f++)
336 {
337 switch (*f)
338 {
339 case 's':
340 {
341 pad = padsize(hsize, sizeof(char *), align);
342 if (pad != 0)
343 {
344 memset(hp, 0, pad);
345 hp += pad;
346 hsize += pad;
347 }
348
349 arg = va_arg(ap, char *);
350 if (arg == NULL)
351 {
352 memset(hp, 0, sizeof(char *));
353 }
354 else
355 {
356 memcpy(hp, &dp, sizeof(char *));
357 slen = strlen(arg) + 1;
358 memcpy(dp, arg, slen);
359 dp += slen;
360 }
361
362 hp += sizeof(char *);
363 hsize += sizeof(char *);
364
365 break;
366 }
367
368 case '1':
369 {
370 u8 = va_arg(ap, int);
371 memcpy(hp, &u8, sizeof(uint8_t));
372 hp += sizeof(uint8_t);
373
374 break;
375 }
376
377 case '2':
378 {
379 pad = padsize(hsize, 2, align);
380 if (pad != 0)
381 {
382 memset(hp, 0, pad);
383 hp += pad;
384 hsize += pad;
385 }
386
387 u16 = va_arg(ap, int);
388 memcpy(hp, &u16, sizeof(uint16_t));
389
390 hp += sizeof(uint16_t);
391 hsize += sizeof(uint16_t);
392
393 break;
394 }
395
396 case '4':
397 {
398 pad = padsize(hsize, 4, align);
399 if (pad != 0)
400 {
401 memset(hp, 0, pad);
402 hp += pad;
403 hsize += pad;
404 }
405
406 u32 = va_arg(ap, uint32_t);
407 memcpy(hp, &u32, sizeof(uint32_t));
408
409 hp += sizeof(uint32_t);
410 hsize += sizeof(uint32_t);
411
412 break;
413 }
414
415 case '8':
416 {
417 pad = padsize(hsize, 8, align);
418 if (pad != 0)
419 {
420 memset(hp, 0, pad);
421 hp += pad;
422 hsize += pad;
423 }
424
425 u64 = va_arg(ap, uint64_t);
426 memcpy(hp, &u64, sizeof(uint64_t));
427
428 hp += sizeof(uint64_t);
429 hsize += sizeof(uint64_t);
430
431 break;
432 }
433
434 case 'S':
435 {
436 pad = padsize(hsize, 4, align);
437 if (pad != 0)
438 {
439 memset(hp, 0, pad);
440 hp += pad;
441 hsize += pad;
442 }
443
444 sdata = va_arg(ap, socket_data_t);
445 memcpy(hp, (char *)(sdata.x), sizeof(socket_data_t));
446
447 hp += sizeof(socket_data_t);
448 hsize += sizeof(socket_data_t);
449
450 break;
451 }
452
453 case 'L':
454 {
455 pad = padsize(hsize, sizeof(unsigned long), align);
456 if (pad != 0)
457 {
458 memset(hp, 0, pad);
459 hp += pad;
460 hsize += pad;
461 }
462
463 l = va_arg(ap, unsigned long);
464 memcpy(hp, &l, sizeof(unsigned long));
465
466 hp += sizeof(unsigned long);
467 hsize += sizeof(unsigned long);
468
469 break;
470 }
471
472 case 'm':
473 {
474 pad = padsize(hsize, sizeof(mach_port_t), align);
475 if (pad != 0)
476 {
477 memset(hp, 0, pad);
478 hp += pad;
479 hsize += pad;
480 }
481
482 m = va_arg(ap, mach_port_t);
483 memcpy(hp, &m, sizeof(mach_port_t));
484
485 hp += sizeof(mach_port_t);
486 hsize += sizeof(mach_port_t);
487
488 break;
489 }
490
491 case '*':
492 {
493 pad = padsize(hsize, sizeof(char *), align);
494 if (pad != 0)
495 {
496 memset(hp, 0, pad);
497 hp += pad;
498 hsize += pad;
499 }
500
501 list = va_arg(ap, char **);
502
503 memcpy(hp, &dp, sizeof(char *));
504
505 for (i = 0; list && list[i] != NULL; i++);
506
507 lp = dp;
508 dp += ((i + 1) * sizeof(char *));
509
510 for (i = 0; list && list[i] != NULL; i++)
511 {
512 memcpy(lp, &dp, sizeof(char *));
513 lp += sizeof(char *);
514 slen = strlen(list[i]) + 1;
515 memcpy(dp, list[i], slen);
516 dp += slen;
517 }
518
519 memset(lp, 0, sizeof(char *));
520
521 hp += sizeof(char *);
522 hsize += sizeof(char *);
523
524 break;
525 }
526
527 case 'a':
528 {
529 pad = padsize(hsize, sizeof(char *), align);
530 if (pad != 0)
531 {
532 memset(hp, 0, pad);
533 hp += pad;
534 hsize += pad;
535 }
536
537 list = va_arg(ap, char **);
538
539 if (list == NULL)
540 {
541 memset(hp, 0, sizeof(char *));
542 }
543 else
544 {
545 memcpy(hp, &dp, sizeof(char *));
546
547 for (i = 0; list[i] != NULL; i++);
548
549 lp = dp;
550 dp += ((i + 1) * sizeof(char *));
551
552 for (i = 0; list[i] != NULL; i++)
553 {
554 memcpy(lp, &dp, sizeof(char *));
555 lp += sizeof(char *);
556 slen = 4;
557 memcpy(dp, list[i], slen);
558 dp += slen;
559 }
560
561 memset(lp, 0, sizeof(char *));
562 }
563
564 hp += sizeof(char *);
565 hsize += sizeof(char *);
566
567 break;
568 }
569
570 case 'b':
571 {
572 pad = padsize(hsize, sizeof(char *), align);
573 if (pad != 0)
574 {
575 memset(hp, 0, pad);
576 hp += pad;
577 hsize += pad;
578 }
579
580 list = va_arg(ap, char **);
581
582 if (list == NULL)
583 {
584 memset(hp, 0, sizeof(char *));
585 }
586 else
587 {
588 memcpy(hp, &dp, sizeof(char *));
589
590 for (i = 0; list[i] != NULL; i++);
591
592 lp = dp;
593 dp += ((i + 1) * sizeof(char *));
594
595 for (i = 0; list[i] != NULL; i++)
596 {
597 memcpy(lp, &dp, sizeof(char *));
598 lp += sizeof(char *);
599 slen = 8;
600 memcpy(dp, list[i], slen);
601 dp += slen;
602 }
603
604 memset(lp, 0, sizeof(char *));
605 }
606
607 hp += sizeof(char *);
608 hsize += sizeof(char *);
609
610 break;
611 }
612
613 case 'c':
614 {
615 pad = padsize(hsize, sizeof(char *), align);
616 if (pad != 0)
617 {
618 memset(hp, 0, pad);
619 hp += pad;
620 hsize += pad;
621 }
622
623 list = va_arg(ap, char **);
624
625 if (list == NULL)
626 {
627 memset(hp, 0, sizeof(char *));
628 }
629 else
630 {
631 memcpy(hp, &dp, sizeof(char *));
632
633 for (i = 0; list[i] != NULL; i++);
634
635 lp = dp;
636 dp += ((i + 1) * sizeof(char *));
637
638 for (i = 0; list[i] != NULL; i++)
639 {
640 memcpy(lp, &dp, sizeof(char *));
641 lp += sizeof(char *);
642 slen = 16;
643 memcpy(dp, list[i], slen);
644 dp += slen;
645 }
646
647 memset(lp, 0, sizeof(char *));
648 }
649
650 hp += sizeof(char *);
651 hsize += sizeof(char *);
652
653 break;
654 }
655
656 case '@':
657 {
658 pad = padsize(hsize, 4, align);
659 if (pad != 0)
660 {
661 memset(hp, 0, pad);
662 hp += pad;
663 hsize += pad;
664 }
665
666 slen = va_arg(ap, uint32_t);
667 memcpy(hp, &slen, sizeof(uint32_t));
668
669 hp += sizeof(uint32_t);
670 hsize += sizeof(uint32_t);
671
672 pad = padsize(hsize, sizeof(char *), align);
673 if (pad != 0)
674 {
675 memset(hp, 0, pad);
676 hp += pad;
677 hsize += pad;
678 }
679
680 arg = va_arg(ap, char *);
681 if (arg == NULL)
682 {
683 memset(hp, 0, sizeof(char *));
684 }
685 else
686 {
687 memcpy(hp, &dp, sizeof(char *));
688 memcpy(dp, arg, slen);
689 dp += slen;
690 }
691
692 hp += sizeof(char *);
693 hsize += sizeof(char *);
694 }
695 }
696 }
697
698 va_end(ap);
699
700 pad = padsize(hsize, largest, align);
701 if (pad > 0) memset(hp, 0, pad);
702
703 return ils;
704 }