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