]> git.saurik.com Git - apple/libc.git/blob - gen/asl_legacy1.c
5a7a000b75e5dffe96c07be6f962a396fca58689
[apple/libc.git] / gen / asl_legacy1.c
1 /*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2007 Apple 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.0 (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 <asl_core.h>
26 #include <asl_legacy1.h>
27 #include <asl_private.h>
28 #include <stdlib.h>
29 #include <sys/file.h>
30 #include <sys/stat.h>
31 #include <sys/errno.h>
32 #include <string.h>
33 #include <membership.h>
34 #include <mach/mach.h>
35 #include <sys/syslimits.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <sys/mman.h>
39
40 #define forever for(;;)
41
42 #define FILE_MODE 0600
43
44 #define DB_RECORD_LEN 80
45
46 #define DB_HEADER_COOKIE_OFFSET 0
47 #define DB_HEADER_VERS_OFFSET 12
48
49 #define DB_TYPE_EMPTY 0
50 #define DB_TYPE_HEADER 1
51 #define DB_TYPE_MESSAGE 2
52 #define DB_TYPE_KVLIST 3
53 #define DB_TYPE_STRING 4
54 #define DB_TYPE_STRCONT 5
55
56 /*
57 * Magic Cookie for database files.
58 * MAXIMUM 12 CHARS! (DB_HEADER_VERS_OFFSET)
59 */
60 #define ASL_DB_COOKIE "ASL DB"
61 #define ASL_DB_COOKIE_LEN 6
62
63 #define ASL_INDEX_NULL 0xffffffff
64
65 #define DB_HLEN_EMPTY 0
66 #define DB_HLEN_HEADER 13
67 #define DB_HLEN_MESSAGE 13
68 #define DB_HLEN_KVLIST 9
69 #define DB_HLEN_STRING 25
70 #define DB_HLEN_STRCONT 5
71
72 #define MSG_OFF_KEY_TYPE 0
73 #define MSG_OFF_KEY_NEXT 1
74 #define MSG_OFF_KEY_ID 5
75 #define MSG_OFF_KEY_RUID 13
76 #define MSG_OFF_KEY_RGID 17
77 #define MSG_OFF_KEY_TIME 21
78 #define MSG_OFF_KEY_HOST 29
79 #define MSG_OFF_KEY_SENDER 37
80 #define MSG_OFF_KEY_FACILITY 45
81 #define MSG_OFF_KEY_LEVEL 53
82 #define MSG_OFF_KEY_PID 57
83 #define MSG_OFF_KEY_UID 61
84 #define MSG_OFF_KEY_GID 65
85 #define MSG_OFF_KEY_MSG 69
86 #define MSG_OFF_KEY_FLAGS 77
87
88 extern time_t asl_parse_time(const char *str);
89 extern int asl_msg_cmp(aslmsg a, aslmsg b);
90
91 #define asl_msg_list_t asl_search_result_t
92
93 #define Q_NULL 100001
94 #define Q_FAST 100002
95 #define Q_SLOW 100003
96 #define Q_FAIL 100004
97
98 static uint64_t
99 _asl_htonq(uint64_t n)
100 {
101 #ifdef __BIG_ENDIAN__
102 return n;
103 #else
104 u_int32_t t;
105 union
106 {
107 u_int64_t q;
108 u_int32_t l[2];
109 } x;
110
111 x.q = n;
112 t = x.l[0];
113 x.l[0] = htonl(x.l[1]);
114 x.l[1] = htonl(t);
115
116 return x.q;
117 #endif
118 }
119
120 static uint64_t
121 _asl_ntohq(uint64_t n)
122 {
123 #ifdef __BIG_ENDIAN__
124 return n;
125 #else
126 u_int32_t t;
127 union
128 {
129 u_int64_t q;
130 u_int32_t l[2];
131 } x;
132
133 x.q = n;
134 t = x.l[0];
135 x.l[0] = ntohl(x.l[1]);
136 x.l[1] = ntohl(t);
137
138 return x.q;
139 #endif
140 }
141
142 static uint16_t
143 _asl_get_16(char *h)
144 {
145 uint16_t x;
146
147 memcpy(&x, h, 2);
148 return ntohs(x);
149 }
150
151 static uint32_t
152 _asl_get_32(char *h)
153 {
154 uint32_t x;
155
156 memcpy(&x, h, 4);
157 return ntohl(x);
158 }
159
160 static uint64_t
161 _asl_get_64(char *h)
162 {
163 uint64_t x;
164
165 memcpy(&x, h, 8);
166 return _asl_ntohq(x);
167 }
168
169 #define header_get_next(h) _asl_get_32(h + 1)
170 #define header_get_id(h) _asl_get_64(h + 5)
171 #define header_get_hash(h) _asl_get_32(h + 17)
172
173 /*
174 * callback for sorting slotlist
175 * primary sort is by xid
176 * secondary sort is by slot, which happens when xid is 0
177 * this allows us to quickly find xids (using binary search on the xid key)
178 * it's also used to find slots quickly from record_chain_free()
179 */
180 static int
181 slot_comp(const void *a, const void *b)
182 {
183 asl_legacy1_slot_info_t *ai, *bi;
184
185 if (a == NULL)
186 {
187 if (b == NULL) return 0;
188 return -1;
189 }
190
191 if (b == NULL) return 1;
192
193 ai = (asl_legacy1_slot_info_t *)a;
194 bi = (asl_legacy1_slot_info_t *)b;
195
196 if (ai->xid < bi->xid) return -1;
197
198 if (ai->xid == bi->xid)
199 {
200 if (ai->slot < bi->slot) return -1;
201 if (ai->slot == bi->slot) return 0;
202 return 1;
203 }
204
205 return 1;
206 }
207
208 /* find an xid in the slot list */
209 static uint32_t
210 slotlist_find(asl_legacy1_t *s, uint64_t xid, int32_t direction)
211 {
212 uint32_t top, bot, mid, range;
213
214 if (s == NULL) return ASL_INDEX_NULL;
215 if (s->slotlist_count == 0) return ASL_INDEX_NULL;
216 if (xid == 0) return ASL_INDEX_NULL;
217
218 top = s->slotlist_count - 1;
219 bot = 0;
220 mid = top / 2;
221
222 range = top - bot;
223 while (range > 1)
224 {
225 if (xid == s->slotlist[mid].xid) return mid;
226 else if (xid < s->slotlist[mid].xid) top = mid;
227 else bot = mid;
228
229 range = top - bot;
230 mid = bot + (range / 2);
231 }
232
233 if (xid == s->slotlist[top].xid) return top;
234 if (xid == s->slotlist[bot].xid) return bot;
235
236 if (direction == 0) return ASL_INDEX_NULL;
237 if (direction < 0) return bot;
238 return top;
239 }
240
241 static uint32_t
242 slotlist_init(asl_legacy1_t *s, uint32_t count)
243 {
244 uint32_t i, si, status, hash, addslot;
245 uint64_t xid;
246 uint8_t t;
247 char tmp[DB_RECORD_LEN];
248
249 /* Start at first slot after the header */
250 status = fseek(s->db, DB_RECORD_LEN, SEEK_SET);
251 if (status != 0) return ASL_STATUS_READ_FAILED;
252
253 s->slotlist = (asl_legacy1_slot_info_t *)calloc(count, sizeof(asl_legacy1_slot_info_t));
254 if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY;
255
256 si = 0;
257
258 for (i = 1; i < count; i++)
259 {
260 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
261 if (status != 1) return ASL_STATUS_READ_FAILED;
262
263 t = tmp[0];
264 addslot = 0;
265 xid = 0;
266 hash = 0;
267
268 if (t == DB_TYPE_EMPTY) addslot = 1;
269
270 if (t == DB_TYPE_STRING)
271 {
272 addslot = 1;
273 xid = header_get_id(tmp);
274 hash = header_get_hash(tmp);
275 }
276
277 if (t == DB_TYPE_MESSAGE)
278 {
279 addslot = 1;
280 xid = header_get_id(tmp);
281 }
282
283 if (addslot == 1)
284 {
285 s->slotlist[si].type = t;
286 s->slotlist[si].slot = i;
287 s->slotlist[si].xid = xid;
288 s->slotlist[si].hash = hash;
289 si++;
290 }
291 }
292
293 s->slotlist = (asl_legacy1_slot_info_t *)reallocf(s->slotlist, si * sizeof(asl_legacy1_slot_info_t));
294 if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY;
295 s->slotlist_count = si;
296
297 /* slotlist is sorted by xid */
298 qsort((void *)s->slotlist, s->slotlist_count, sizeof(asl_legacy1_slot_info_t), slot_comp);
299
300 return ASL_STATUS_OK;
301 }
302
303 uint32_t
304 asl_legacy1_open(const char *path, asl_legacy1_t **out)
305 {
306 asl_legacy1_t *s;
307 struct stat sb;
308 int status;
309 char cbuf[DB_RECORD_LEN];
310 off_t fsize;
311 uint32_t count;
312
313 memset(&sb, 0, sizeof(struct stat));
314 status = stat(path, &sb);
315 if (status < 0) return ASL_STATUS_FAILED;
316
317 fsize = sb.st_size;
318
319 s = (asl_legacy1_t *)calloc(1, sizeof(asl_legacy1_t));
320 if (s == NULL) return ASL_STATUS_NO_MEMORY;
321
322 s->db = fopen(path, "r");
323 if (s->db == NULL)
324 {
325 free(s);
326 return ASL_STATUS_INVALID_STORE;
327 }
328
329 memset(cbuf, 0, DB_RECORD_LEN);
330 status = fread(cbuf, DB_RECORD_LEN, 1, s->db);
331 if (status != 1)
332 {
333 fclose(s->db);
334 free(s);
335 return ASL_STATUS_READ_FAILED;
336 }
337
338 /* Check the database Magic Cookie */
339 if (strncmp(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
340 {
341 fclose(s->db);
342 free(s);
343 return ASL_STATUS_INVALID_STORE;
344 }
345
346 count = fsize / DB_RECORD_LEN;
347
348 status = slotlist_init(s, count);
349
350 *out = s;
351 return ASL_STATUS_OK;
352 }
353
354 uint32_t
355 asl_legacy1_close(asl_legacy1_t *s)
356 {
357 if (s == NULL) return ASL_STATUS_INVALID_STORE;
358
359 if (s->slotlist != NULL) free(s->slotlist);
360 if (s->db != NULL) fclose(s->db);
361 free(s);
362
363 return ASL_STATUS_OK;
364 }
365
366 static uint32_t
367 string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out)
368 {
369 off_t offset;
370 uint8_t type;
371 uint32_t status, next, len, x, remaining;
372 char *outstr, *p, tmp[DB_RECORD_LEN];
373
374 if (s == NULL) return ASL_STATUS_INVALID_STORE;
375 if (out == NULL) return ASL_STATUS_INVALID_ARG;
376
377 *out = NULL;
378 offset = slot * DB_RECORD_LEN;
379 status = fseek(s->db, offset, SEEK_SET);
380
381 if (status < 0) return ASL_STATUS_READ_FAILED;
382
383 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
384 if (status != 1) return ASL_STATUS_READ_FAILED;
385
386 type = tmp[0];
387 if (type != DB_TYPE_STRING) return ASL_STATUS_INVALID_STRING;
388
389 len = _asl_get_32(tmp + 21);
390 if (len == 0) return ASL_STATUS_OK;
391
392 next = header_get_next(tmp);
393
394 outstr = calloc(1, len);
395 if (outstr == NULL) return ASL_STATUS_NO_MEMORY;
396
397 p = outstr;
398 remaining = len;
399
400 x = DB_RECORD_LEN - DB_HLEN_STRING;
401 if (x > remaining) x = remaining;
402
403 memcpy(p, tmp + DB_HLEN_STRING, x);
404 p += x;
405 remaining -= x;
406
407 while ((next != 0) && (remaining > 0))
408 {
409 offset = next * DB_RECORD_LEN;
410 status = fseek(s->db, offset, SEEK_SET);
411
412 if (status < 0)
413 {
414 free(outstr);
415 return ASL_STATUS_READ_FAILED;
416 }
417
418 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
419 if (status != 1)
420 {
421 free(outstr);
422 return ASL_STATUS_READ_FAILED;
423 }
424
425 next = header_get_next(tmp);
426
427 x = DB_RECORD_LEN - DB_HLEN_STRCONT;
428 if (x > remaining) x = remaining;
429
430 memcpy(p, tmp + DB_HLEN_STRCONT, x);
431 p += x;
432 remaining -= x;
433 }
434
435 if ((next != 0) || (remaining != 0))
436 {
437 free(outstr);
438 return ASL_STATUS_READ_FAILED;
439 }
440
441 *out = outstr;
442 return ASL_STATUS_OK;
443 }
444
445 static uint32_t
446 string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out)
447 {
448 uint32_t i, len, ref;
449 uint64_t nsid;
450 uint8_t inls;
451 char *p;
452
453 if (s == NULL) return ASL_STATUS_INVALID_STORE;
454 if (out == NULL) return ASL_STATUS_INVALID_ARG;
455
456 *out = NULL;
457 if (sid == ASL_REF_NULL) return ASL_STATUS_OK;
458
459 ref = 0;
460
461 inls = 0;
462 nsid = _asl_htonq(sid);
463 memcpy(&inls, &nsid, 1);
464 if (inls & 0x80)
465 {
466 /* inline string */
467 inls &= 0x0f;
468 len = inls;
469 *out = calloc(1, len);
470 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
471 p = 1 + (char *)&nsid;
472 memcpy(*out, p, len);
473 return ASL_STATUS_OK;
474 }
475
476 /* Find the string in the database */
477 i = slotlist_find(s, sid, 0);
478 if (i == ASL_INDEX_NULL) return ASL_STATUS_NOT_FOUND;
479
480 return string_fetch_slot(s, s->slotlist[i].slot, out);
481 }
482
483 static uint32_t
484 asl_legacy1_fetch_helper_32(asl_legacy1_t *s, char **p, aslmsg m, const char *key, int ignore, uint32_t ignoreval)
485 {
486 uint32_t out, doit;
487 char str[256];
488
489 out = _asl_get_32(*p);
490 *p += sizeof(uint32_t);
491
492 if ((m == NULL) || (key == NULL)) return out;
493
494 doit = 1;
495 if ((ignore != 0) && (out == ignoreval)) doit = 0;
496 if (doit != 0)
497 {
498 snprintf(str, sizeof(str), "%u", out);
499 asl_set(m, key, str);
500 }
501
502 return out;
503 }
504
505 static uint64_t
506 asl_legacy1_fetch_helper_64(asl_legacy1_t *s, char **p, aslmsg m, const char *key)
507 {
508 uint64_t out;
509 char str[256];
510
511 out = _asl_get_64(*p);
512 *p += sizeof(uint64_t);
513
514 if ((m == NULL) || (key == NULL)) return out;
515
516 snprintf(str, sizeof(str), "%llu", out);
517 asl_set(m, key, str);
518
519 return out;
520 }
521
522 static uint64_t
523 asl_legacy1_fetch_helper_str(asl_legacy1_t *s, char **p, aslmsg m, const char *key, uint32_t *err)
524 {
525 uint64_t out;
526 char *val;
527 uint32_t status;
528
529 out = _asl_get_64(*p);
530 *p += sizeof(uint64_t);
531
532 val = NULL;
533 status = ASL_STATUS_OK;
534 if (out != 0) status = string_fetch_sid(s, out, &val);
535
536 if (err != NULL) *err = status;
537 if ((status == ASL_STATUS_OK) && (val != NULL))
538 {
539 asl_set(m, key, val);
540 free(val);
541 }
542
543 return out;
544 }
545
546 static uint32_t
547 msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out)
548 {
549 off_t offset;
550 uint32_t status, i, n, kvcount, next;
551 uint16_t flags;
552 uint64_t sid;
553 aslmsg msg;
554 char *p, tmp[DB_RECORD_LEN], *key, *val;
555
556 if (s == NULL) return ASL_STATUS_INVALID_STORE;
557 if (out == NULL) return ASL_STATUS_INVALID_ARG;
558
559 *out = NULL;
560
561 offset = slot * DB_RECORD_LEN;
562 status = fseek(s->db, offset, SEEK_SET);
563
564 if (status < 0) return ASL_STATUS_READ_FAILED;
565
566 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
567 if (status != 1) return ASL_STATUS_READ_FAILED;
568
569 flags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS);
570
571 msg = asl_new(ASL_TYPE_MSG);
572 if (msg == NULL) return ASL_STATUS_NO_MEMORY;
573
574 p = tmp + 5;
575
576 asl_legacy1_fetch_helper_64(s, &p, msg, ASL_KEY_MSG_ID);
577 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_READ_UID, 1, (uint32_t)-1);
578 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_READ_GID, 1, (uint32_t)-1);
579 asl_legacy1_fetch_helper_64(s, &p, msg, ASL_KEY_TIME);
580 asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_HOST, &status);
581 asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_SENDER, &status);
582 asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_FACILITY, &status);
583 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_LEVEL, 0, 0);
584 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_PID, 0, 0);
585 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_UID, 0, 0);
586 asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_GID, 0, 0);
587 asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_MSG, &status);
588
589 next = header_get_next(tmp);
590
591 kvcount = 0;
592 n = 0;
593
594 while (next != 0)
595 {
596 offset = next * DB_RECORD_LEN;
597 status = fseek(s->db, offset, SEEK_SET);
598 if (status < 0)
599 {
600 free(out);
601 return ASL_STATUS_READ_FAILED;
602 }
603
604 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
605 if (status != 1)
606 {
607 free(out);
608 return ASL_STATUS_READ_FAILED;
609 }
610
611 if (kvcount == 0) kvcount = _asl_get_32(tmp + 5);
612
613 p = tmp + 9;
614
615 for (i = 0; (i < 4) && (n < kvcount); i++)
616 {
617 key = NULL;
618 sid = _asl_get_64(p);
619 p += 8;
620 status = string_fetch_sid(s, sid, &key);
621
622 val = NULL;
623 sid = _asl_get_64(p);
624 p += 8;
625 if (status == ASL_STATUS_OK) status = string_fetch_sid(s, sid, &val);
626
627 if ((status == ASL_STATUS_OK) && (key != NULL)) asl_set(msg, key, val);
628 if (key != NULL) free(key);
629 if (val != NULL) free(val);
630
631 n++;
632 }
633
634 next = header_get_next(tmp);
635 }
636
637 *out = msg;
638 return ASL_STATUS_OK;
639 }
640
641 uint32_t
642 asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, aslmsg *out)
643 {
644 uint32_t i, status;
645
646 if (s == NULL) return ASL_STATUS_INVALID_STORE;
647 if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG;
648 if (out == NULL) return ASL_STATUS_INVALID_ARG;
649
650 i = slotlist_find(s, msgid, 0);
651 if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID;
652
653 /* read the message */
654 status = msg_fetch(s, s->slotlist[i].slot, out);
655 if (status != ASL_STATUS_OK) return status;
656 if (*out == NULL) return ASL_STATUS_FAILED;
657
658 return status;
659 }
660
661 static uint32_t
662 next_search_slot(asl_legacy1_t *s, uint32_t last_si, int32_t direction)
663 {
664 uint32_t i;
665
666 if (direction >= 0)
667 {
668 for (i = last_si + 1; i < s->slotlist_count; i++)
669 {
670 if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i;
671 }
672
673 return ASL_INDEX_NULL;
674 }
675
676 if (last_si == 0) return ASL_INDEX_NULL;
677 if (last_si > s->slotlist_count) return ASL_INDEX_NULL;
678
679 for (i = last_si - 1; i > 0; i--)
680 {
681 if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i;
682 }
683
684 if (s->slotlist[0].type == DB_TYPE_MESSAGE) return 0;
685
686 return ASL_INDEX_NULL;
687 }
688
689 static void
690 match_worker_cleanup(asl_msg_list_t **res)
691 {
692 uint32_t i;
693
694 if (res != NULL)
695 {
696 for (i = 0; i < (*res)->count; i++) asl_free((aslmsg)(*res)->msg[i]);
697 free(*res);
698 }
699 }
700
701 /*
702 * Input to asl_legacy1_match is a list of queries.
703 * A record in the store matches if it matches any query (i.e. query list is "OR"ed)
704 *
705 * If counting up (direction is positive) find first record with ID > start_id.
706 * Else if counting down (direction is negative) find first record with ID < start_id.
707 *
708 * Set match flag on.
709 * If any query is NULL, set match flog off (skips matching below).
710 * Else if all queries only check "standard" keys, set std flag to on.
711 *
712 * If all queries are marked as "never matches", return NULL.
713 *
714 * match loop:
715 * fetch record (with std flag)
716 * if match flag is off, decode record and add it to result.
717 * else for each query:
718 * if query is NULL (shouldn't happen) decode record and add it to result. Return to match loop.
719 * else if query never matches, ignore it.
720 * else decode record and use asl_cmp. If it succeeds, add record to result. Return to match loop.
721 *
722 * return results.
723 */
724 static uint32_t
725 match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t **idlist, uint32_t *idcount, uint64_t start_id, int32_t count, int32_t direction)
726 {
727 uint32_t mx, si, slot, i, qcount, match, didmatch, status;
728 uint64_t xid;
729 aslmsg msg;
730
731 if (s == NULL) return ASL_STATUS_INVALID_STORE;
732 if ((res == NULL) && (idlist == NULL)) return ASL_STATUS_INVALID_ARG;
733 if (last_id == NULL) return ASL_STATUS_INVALID_ARG;
734 if (idcount == NULL) return ASL_STATUS_INVALID_ARG;
735
736 if (res != NULL) *res = NULL;
737 if (idlist != NULL) *idlist = NULL;
738
739 mx = 0;
740
741 if (direction < 0) direction = -1;
742 else direction = 1;
743
744 si = ASL_INDEX_NULL;
745 if ((direction == -1) && (start_id == ASL_REF_NULL)) si = s->slotlist_count;
746 else si = slotlist_find(s, start_id, direction);
747
748 si = next_search_slot(s, si, direction);
749 if (si == ASL_INDEX_NULL) return ASL_STATUS_OK;
750 if (si >= s->slotlist_count) return ASL_STATUS_FAILED;
751
752 slot = s->slotlist[si].slot;
753
754 match = 1;
755 qcount = 0;
756
757 if (query == NULL) match = 0;
758 else if (query->count == 0) match = 0;
759 else qcount = query->count;
760
761 /*
762 * initialize result list if we've been asked to return messages
763 */
764 if (res != NULL)
765 {
766 *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
767 if (*res == NULL) return ASL_STATUS_NO_MEMORY;
768 }
769
770 status = ASL_STATUS_OK;
771
772 /*
773 * loop through records
774 */
775 *idcount = 0;
776 while ((count == 0) || (*idcount < count))
777 {
778 if (si == ASL_INDEX_NULL) break;
779 if (si >= s->slotlist_count) break;
780
781 slot = s->slotlist[si].slot;
782 xid = s->slotlist[si].xid;
783
784 *last_id = xid;
785
786 status = msg_fetch(s, slot, &msg);
787
788 didmatch = 0;
789 if (match == 0)
790 {
791 didmatch = 1;
792 }
793 else
794 {
795 for (i = 0; i < qcount; i++)
796 {
797 didmatch = asl_msg_cmp((aslmsg)(query->msg[i]), msg);
798 if (didmatch == 1) break;
799 }
800 }
801
802 if (didmatch == 1)
803 {
804 if ((*res)->count == 0) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
805 else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, (1 + (*res)->count) * sizeof(asl_msg_t *));
806 if ((*res)->msg == NULL)
807 {
808 match_worker_cleanup(res);
809 return ASL_STATUS_NO_MEMORY;
810 }
811
812 (*res)->msg[(*res)->count++] = (asl_msg_t *)msg;
813 }
814 else
815 {
816 asl_free(msg);
817 }
818
819 si = next_search_slot(s, si, direction);
820 }
821
822 return status;
823 }
824
825 uint32_t
826 asl_legacy1_match(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
827 {
828 uint32_t idcount;
829
830 idcount = 0;
831 return match_worker(s, query, res, last_id, NULL, &idcount, start_id, count, direction);
832 }