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