]> git.saurik.com Git - apple/libc.git/blame_incremental - gen/asl_legacy1.c
Libc-594.1.4.tar.gz
[apple/libc.git] / gen / asl_legacy1.c
... / ...
CommitLineData
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
88extern time_t asl_parse_time(const char *str);
89extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
90
91#define asl_msg_list_t asl_search_result_t
92
93#define PMSG_SEL_TIME 0x0001
94#define PMSG_SEL_HOST 0x0002
95#define PMSG_SEL_SENDER 0x0004
96#define PMSG_SEL_FACILITY 0x0008
97#define PMSG_SEL_MESSAGE 0x0010
98#define PMSG_SEL_LEVEL 0x0020
99#define PMSG_SEL_PID 0x0040
100#define PMSG_SEL_UID 0x0080
101#define PMSG_SEL_GID 0x0100
102#define PMSG_SEL_RUID 0x0200
103#define PMSG_SEL_RGID 0x0400
104
105#define PMSG_FETCH_ALL 0
106#define PMSG_FETCH_STD 1
107#define PMSG_FETCH_KV 2
108
109#define Q_NULL 100001
110#define Q_FAST 100002
111#define Q_SLOW 100003
112#define Q_FAIL 100004
113
114typedef struct
115{
116 uint16_t kselect;
117 uint16_t vselect;
118 uint64_t msgid;
119 uint64_t time;
120 uint64_t host;
121 uint64_t sender;
122 uint64_t facility;
123 uint64_t message;
124 uint32_t level;
125 uint32_t pid;
126 int32_t uid;
127 int32_t gid;
128 int32_t ruid;
129 int32_t rgid;
130 uint32_t next;
131 uint32_t kvcount;
132 uint64_t *kvlist;
133} pmsg_t;
134
135static uint64_t
136_asl_htonq(uint64_t n)
137{
138#ifdef __BIG_ENDIAN__
139 return n;
140#else
141 u_int32_t t;
142 union
143 {
144 u_int64_t q;
145 u_int32_t l[2];
146 } x;
147
148 x.q = n;
149 t = x.l[0];
150 x.l[0] = htonl(x.l[1]);
151 x.l[1] = htonl(t);
152
153 return x.q;
154#endif
155}
156
157static uint64_t
158_asl_ntohq(uint64_t n)
159{
160#ifdef __BIG_ENDIAN__
161 return n;
162#else
163 u_int32_t t;
164 union
165 {
166 u_int64_t q;
167 u_int32_t l[2];
168 } x;
169
170 x.q = n;
171 t = x.l[0];
172 x.l[0] = ntohl(x.l[1]);
173 x.l[1] = ntohl(t);
174
175 return x.q;
176#endif
177}
178
179static uint16_t
180_asl_get_16(char *h)
181{
182 uint16_t x;
183
184 memcpy(&x, h, 2);
185 return ntohs(x);
186}
187
188static uint32_t
189_asl_get_32(char *h)
190{
191 uint32_t x;
192
193 memcpy(&x, h, 4);
194 return ntohl(x);
195}
196
197static uint64_t
198_asl_get_64(char *h)
199{
200 uint64_t x;
201
202 memcpy(&x, h, 8);
203 return _asl_ntohq(x);
204}
205
206#define header_get_next(h) _asl_get_32(h + 1)
207#define header_get_id(h) _asl_get_64(h + 5)
208#define header_get_hash(h) _asl_get_32(h + 17)
209
210/*
211 * callback for sorting slotlist
212 * primary sort is by xid
213 * secondary sort is by slot, which happens when xid is 0
214 * this allows us to quickly find xids (using binary search on the xid key)
215 * it's also used to find slots quickly from record_chain_free()
216 */
217static int
218slot_comp(const void *a, const void *b)
219{
220 asl_legacy1_slot_info_t *ai, *bi;
221
222 if (a == NULL)
223 {
224 if (b == NULL) return 0;
225 return -1;
226 }
227
228 if (b == NULL) return 1;
229
230 ai = (asl_legacy1_slot_info_t *)a;
231 bi = (asl_legacy1_slot_info_t *)b;
232
233 if (ai->xid < bi->xid) return -1;
234
235 if (ai->xid == bi->xid)
236 {
237 if (ai->slot < bi->slot) return -1;
238 if (ai->slot == bi->slot) return 0;
239 return 1;
240 }
241
242 return 1;
243}
244
245/* find an xid in the slot list */
246static uint32_t
247slotlist_find(asl_legacy1_t *s, uint64_t xid, int32_t direction)
248{
249 uint32_t top, bot, mid, range;
250
251 if (s == NULL) return ASL_INDEX_NULL;
252 if (s->slotlist_count == 0) return ASL_INDEX_NULL;
253 if (xid == 0) return ASL_INDEX_NULL;
254
255 top = s->slotlist_count - 1;
256 bot = 0;
257 mid = top / 2;
258
259 range = top - bot;
260 while (range > 1)
261 {
262 if (xid == s->slotlist[mid].xid) return mid;
263 else if (xid < s->slotlist[mid].xid) top = mid;
264 else bot = mid;
265
266 range = top - bot;
267 mid = bot + (range / 2);
268 }
269
270 if (xid == s->slotlist[top].xid) return top;
271 if (xid == s->slotlist[bot].xid) return bot;
272
273 if (direction == 0) return ASL_INDEX_NULL;
274 if (direction < 0) return bot;
275 return top;
276}
277
278static uint32_t
279slotlist_init(asl_legacy1_t *s, uint32_t count)
280{
281 uint32_t i, si, status, hash, addslot;
282 uint64_t xid;
283 uint8_t t;
284 char tmp[DB_RECORD_LEN];
285
286 /* Start at first slot after the header */
287 status = fseek(s->db, DB_RECORD_LEN, SEEK_SET);
288 if (status != 0) return ASL_STATUS_READ_FAILED;
289
290 s->slotlist = (asl_legacy1_slot_info_t *)calloc(count, sizeof(asl_legacy1_slot_info_t));
291 if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY;
292
293 si = 0;
294
295 for (i = 1; i < count; i++)
296 {
297 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
298 if (status != 1) return ASL_STATUS_READ_FAILED;
299
300 t = tmp[0];
301 addslot = 0;
302 xid = 0;
303 hash = 0;
304
305 if (t == DB_TYPE_EMPTY) addslot = 1;
306
307 if (t == DB_TYPE_STRING)
308 {
309 addslot = 1;
310 xid = header_get_id(tmp);
311 hash = header_get_hash(tmp);
312 }
313
314 if (t == DB_TYPE_MESSAGE)
315 {
316 addslot = 1;
317 xid = header_get_id(tmp);
318 }
319
320 if (addslot == 1)
321 {
322 s->slotlist[si].type = t;
323 s->slotlist[si].slot = i;
324 s->slotlist[si].xid = xid;
325 s->slotlist[si].hash = hash;
326 si++;
327 }
328 }
329
330 s->slotlist = (asl_legacy1_slot_info_t *)reallocf(s->slotlist, si * sizeof(asl_legacy1_slot_info_t));
331 if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY;
332 s->slotlist_count = si;
333
334 /* slotlist is sorted by xid */
335 qsort((void *)s->slotlist, s->slotlist_count, sizeof(asl_legacy1_slot_info_t), slot_comp);
336
337 return ASL_STATUS_OK;
338}
339
340uint32_t
341asl_legacy1_open(const char *path, asl_legacy1_t **out)
342{
343 asl_legacy1_t *s;
344 struct stat sb;
345 int status;
346 char cbuf[DB_RECORD_LEN];
347 off_t fsize;
348 uint32_t count;
349
350 memset(&sb, 0, sizeof(struct stat));
351 status = stat(path, &sb);
352 if (status < 0) return ASL_STATUS_FAILED;
353
354 fsize = sb.st_size;
355
356 s = (asl_legacy1_t *)calloc(1, sizeof(asl_legacy1_t));
357 if (s == NULL) return ASL_STATUS_NO_MEMORY;
358
359 s->db = fopen(path, "r");
360 if (s->db == NULL)
361 {
362 free(s);
363 return ASL_STATUS_INVALID_STORE;
364 }
365
366 memset(cbuf, 0, DB_RECORD_LEN);
367 status = fread(cbuf, DB_RECORD_LEN, 1, s->db);
368 if (status != 1)
369 {
370 fclose(s->db);
371 free(s);
372 return ASL_STATUS_READ_FAILED;
373 }
374
375 /* Check the database Magic Cookie */
376 if (strncmp(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
377 {
378 fclose(s->db);
379 free(s);
380 return ASL_STATUS_INVALID_STORE;
381 }
382
383 count = fsize / DB_RECORD_LEN;
384
385 status = slotlist_init(s, count);
386
387 *out = s;
388 return ASL_STATUS_OK;
389}
390
391uint32_t
392asl_legacy1_close(asl_legacy1_t *s)
393{
394 if (s == NULL) return ASL_STATUS_INVALID_STORE;
395
396 if (s->slotlist != NULL) free(s->slotlist);
397 if (s->db != NULL) fclose(s->db);
398 free(s);
399
400 return ASL_STATUS_OK;
401}
402
403static uint32_t
404string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out)
405{
406 off_t offset;
407 uint8_t type;
408 uint32_t status, next, len, x, remaining;
409 char *outstr, *p, tmp[DB_RECORD_LEN];
410
411 if (s == NULL) return ASL_STATUS_INVALID_STORE;
412 if (out == NULL) return ASL_STATUS_INVALID_ARG;
413
414 *out = NULL;
415 offset = slot * DB_RECORD_LEN;
416 status = fseek(s->db, offset, SEEK_SET);
417
418 if (status < 0) return ASL_STATUS_READ_FAILED;
419
420 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
421 if (status != 1) return ASL_STATUS_READ_FAILED;
422
423 type = tmp[0];
424 if (type != DB_TYPE_STRING) return ASL_STATUS_INVALID_STRING;
425
426 len = _asl_get_32(tmp + 21);
427 if (len == 0) return ASL_STATUS_OK;
428
429 next = header_get_next(tmp);
430
431 outstr = calloc(1, len);
432 if (outstr == NULL) return ASL_STATUS_NO_MEMORY;
433
434 p = outstr;
435 remaining = len;
436
437 x = DB_RECORD_LEN - DB_HLEN_STRING;
438 if (x > remaining) x = remaining;
439
440 memcpy(p, tmp + DB_HLEN_STRING, x);
441 p += x;
442 remaining -= x;
443
444 while ((next != 0) && (remaining > 0))
445 {
446 offset = next * DB_RECORD_LEN;
447 status = fseek(s->db, offset, SEEK_SET);
448
449 if (status < 0)
450 {
451 free(outstr);
452 return ASL_STATUS_READ_FAILED;
453 }
454
455 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
456 if (status != 1)
457 {
458 free(outstr);
459 return ASL_STATUS_READ_FAILED;
460 }
461
462 next = header_get_next(tmp);
463
464 x = DB_RECORD_LEN - DB_HLEN_STRCONT;
465 if (x > remaining) x = remaining;
466
467 memcpy(p, tmp + DB_HLEN_STRCONT, x);
468 p += x;
469 remaining -= x;
470 }
471
472 if ((next != 0) || (remaining != 0))
473 {
474 free(outstr);
475 return ASL_STATUS_READ_FAILED;
476 }
477
478 *out = outstr;
479 return ASL_STATUS_OK;
480}
481
482static uint32_t
483string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out)
484{
485 uint32_t i, len, ref;
486 uint64_t nsid;
487 uint8_t inls;
488 char *p;
489
490 if (s == NULL) return ASL_STATUS_INVALID_STORE;
491 if (out == NULL) return ASL_STATUS_INVALID_ARG;
492
493 *out = NULL;
494 if (sid == ASL_REF_NULL) return ASL_STATUS_OK;
495
496 ref = 0;
497
498 inls = 0;
499 nsid = _asl_htonq(sid);
500 memcpy(&inls, &nsid, 1);
501 if (inls & 0x80)
502 {
503 /* inline string */
504 inls &= 0x0f;
505 len = inls;
506 *out = calloc(1, len);
507 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
508 p = 1 + (char *)&nsid;
509 memcpy(*out, p, len);
510 return ASL_STATUS_OK;
511 }
512
513 /* Find the string in the database */
514 i = slotlist_find(s, sid, 0);
515 if (i == ASL_INDEX_NULL) return ASL_STATUS_NOT_FOUND;
516
517 return string_fetch_slot(s, s->slotlist[i].slot, out);
518}
519
520static uint32_t
521pmsg_fetch(asl_legacy1_t *s, uint32_t slot, uint32_t action, pmsg_t **pmsg)
522{
523 off_t offset;
524 uint32_t status, i, n, v32, next;
525 int32_t msgu, msgg;
526 uint64_t msgid;
527 uint16_t flags;
528 pmsg_t *out;
529 char *p, tmp[DB_RECORD_LEN];
530
531 if (s == NULL) return ASL_STATUS_INVALID_STORE;
532 if (pmsg == NULL) return ASL_STATUS_INVALID_ARG;
533
534 out = NULL;
535
536 if ((action == PMSG_FETCH_ALL) || (action == PMSG_FETCH_STD))
537 {
538 *pmsg = NULL;
539
540 offset = slot * DB_RECORD_LEN;
541 status = fseek(s->db, offset, SEEK_SET);
542
543 if (status < 0) return ASL_STATUS_READ_FAILED;
544
545 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
546 if (status != 1) return ASL_STATUS_READ_FAILED;
547
548 msgid = _asl_get_64(tmp + MSG_OFF_KEY_ID);
549 msgu = _asl_get_32(tmp + MSG_OFF_KEY_RUID);
550 msgg = _asl_get_32(tmp + MSG_OFF_KEY_RGID);
551 flags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS);
552
553 out = (pmsg_t *)calloc(1, sizeof(pmsg_t));
554 if (out == NULL) return ASL_STATUS_NO_MEMORY;
555
556
557 p = tmp + 21;
558
559 /* ID */
560 out->msgid = msgid;
561
562 /* ReadUID */
563 out->ruid = msgu;
564
565 /* ReadGID */
566 out->rgid = msgg;
567
568 /* Time */
569 out->time = _asl_get_64(p);
570 p += 8;
571
572 /* Host */
573 out->host = _asl_get_64(p);
574 p += 8;
575
576 /* Sender */
577 out->sender = _asl_get_64(p);
578 p += 8;
579
580 /* Facility */
581 out->facility = _asl_get_64(p);
582 p += 8;
583
584 /* Level */
585 out->level = _asl_get_32(p);
586 p += 4;
587
588 /* PID */
589 out->pid = _asl_get_32(p);
590 p += 4;
591
592 /* UID */
593 out->uid = _asl_get_32(p);
594 p += 4;
595
596 /* GID */
597 out->gid = _asl_get_32(p);
598 p += 4;
599
600 /* Message */
601 out->message = _asl_get_64(p);
602 p += 8;
603
604 next = header_get_next(tmp);
605 out->next = next;
606
607 if (action == PMSG_FETCH_STD)
608 {
609 /* caller only wants "standard" keys */
610 *pmsg = out;
611 return ASL_STATUS_OK;
612 }
613
614 *pmsg = out;
615 }
616 else
617 {
618 out = *pmsg;
619 }
620
621 n = 0;
622 next = out->next;
623
624 while (next != 0)
625 {
626 offset = next * DB_RECORD_LEN;
627 status = fseek(s->db, offset, SEEK_SET);
628 if (status < 0)
629 {
630 *pmsg = NULL;
631 free(out);
632 return ASL_STATUS_READ_FAILED;
633 }
634
635 status = fread(tmp, DB_RECORD_LEN, 1, s->db);
636 if (status != 1)
637 {
638 *pmsg = NULL;
639 free(out);
640 return ASL_STATUS_READ_FAILED;
641 }
642
643 if (out->kvcount == 0)
644 {
645 v32 = _asl_get_32(tmp + 5);
646 out->kvcount = v32 * 2;
647 out->kvlist = (uint64_t *)calloc(out->kvcount, sizeof(uint64_t));
648 if (out->kvlist == NULL)
649 {
650 *pmsg = NULL;
651 free(out);
652 return ASL_STATUS_NO_MEMORY;
653 }
654 }
655
656 p = tmp + 9;
657
658 for (i = 0; (i < 4) && (n < out->kvcount); i++)
659 {
660 out->kvlist[n++] = _asl_get_64(p);
661 p += 8;
662
663 out->kvlist[n++] = _asl_get_64(p);
664 p += 8;
665 }
666
667 next = header_get_next(tmp);
668 }
669
670 return ASL_STATUS_OK;
671}
672
673static uint32_t
674pmsg_match(asl_legacy1_t *s, pmsg_t *q, pmsg_t *m)
675{
676 uint32_t i, j;
677
678 if (s == NULL) return 0;
679 if (q == NULL) return 1;
680 if (m == NULL) return 0;
681
682 if (q->kselect & PMSG_SEL_TIME)
683 {
684 if (q->time == ASL_REF_NULL) return 0;
685 if ((q->vselect & PMSG_SEL_TIME) && (q->time != m->time)) return 0;
686 }
687
688 if (q->kselect & PMSG_SEL_HOST)
689 {
690 if (q->host == ASL_REF_NULL) return 0;
691 if ((q->vselect & PMSG_SEL_HOST) && (q->host != m->host)) return 0;
692 }
693
694 if (q->kselect & PMSG_SEL_SENDER)
695 {
696 if (q->sender == ASL_REF_NULL) return 0;
697 if ((q->vselect & PMSG_SEL_SENDER) && (q->sender != m->sender)) return 0;
698 }
699
700 if (q->kselect & PMSG_SEL_FACILITY)
701 {
702 if (q->facility == ASL_REF_NULL) return 0;
703 if ((q->vselect & PMSG_SEL_FACILITY) && (q->facility != m->facility)) return 0;
704 }
705
706 if (q->kselect & PMSG_SEL_MESSAGE)
707 {
708 if (q->message == ASL_REF_NULL) return 0;
709 if ((q->vselect & PMSG_SEL_MESSAGE) && (q->message != m->message)) return 0;
710 }
711
712 if (q->kselect & PMSG_SEL_LEVEL)
713 {
714 if (q->level == ASL_INDEX_NULL) return 0;
715 if ((q->vselect & PMSG_SEL_LEVEL) && (q->level != m->level)) return 0;
716 }
717
718 if (q->kselect & PMSG_SEL_PID)
719 {
720 if (q->pid == -1) return 0;
721 if ((q->vselect & PMSG_SEL_PID) && (q->pid != m->pid)) return 0;
722 }
723
724 if (q->kselect & PMSG_SEL_UID)
725 {
726 if (q->uid == -2) return 0;
727 if ((q->vselect & PMSG_SEL_UID) && (q->uid != m->uid)) return 0;
728 }
729
730 if (q->kselect & PMSG_SEL_GID)
731 {
732 if (q->gid == -2) return 0;
733 if ((q->vselect & PMSG_SEL_GID) && (q->gid != m->gid)) return 0;
734 }
735
736 if (q->kselect & PMSG_SEL_RUID)
737 {
738 if (q->ruid == -1) return 0;
739 if ((q->vselect & PMSG_SEL_RUID) && (q->ruid != m->ruid)) return 0;
740 }
741
742 if (q->kselect & PMSG_SEL_RGID)
743 {
744 if (q->rgid == -1) return 0;
745 if ((q->vselect & PMSG_SEL_RGID) && (q->rgid != m->rgid)) return 0;
746 }
747
748 for (i = 0; i < q->kvcount; i += 2)
749 {
750 for (j = 0; j < m->kvcount; j += 2)
751 {
752 if (q->kvlist[i] == m->kvlist[j])
753 {
754 if (q->kvlist[i + 1] == m->kvlist[j + 1]) break;
755 return 0;
756 }
757 }
758
759 if (j >= m->kvcount) return 0;
760 }
761
762 return 1;
763}
764
765static void
766free_pmsg(pmsg_t *p)
767{
768 if (p == NULL) return;
769 if (p->kvlist != NULL) free(p->kvlist);
770 free(p);
771}
772
773static uint32_t
774pmsg_fetch_by_id(asl_legacy1_t *s, uint64_t msgid, pmsg_t **pmsg, uint32_t *slot)
775{
776 uint32_t i, status;
777
778 if (s == NULL) return ASL_STATUS_INVALID_STORE;
779 if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG;
780 if (slot == NULL) return ASL_STATUS_INVALID_ARG;
781
782 *slot = ASL_INDEX_NULL;
783
784 i = slotlist_find(s, msgid, 0);
785 if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID;
786
787 *slot = s->slotlist[i].slot;
788
789 /* read the message */
790 *pmsg = NULL;
791 status = pmsg_fetch(s, s->slotlist[i].slot, PMSG_FETCH_ALL, pmsg);
792 if (status != ASL_STATUS_OK) return status;
793 if (pmsg == NULL) return ASL_STATUS_FAILED;
794
795 return status;
796}
797
798static uint32_t
799msg_decode(asl_legacy1_t *s, pmsg_t *pmsg, asl_msg_t **out)
800{
801 uint32_t status, i, n;
802 char *key, *val;
803 asl_msg_t *msg;
804
805 if (s == NULL) return ASL_STATUS_INVALID_STORE;
806 if (out == NULL) return ASL_STATUS_INVALID_ARG;
807 if (pmsg == NULL) return ASL_STATUS_INVALID_ARG;
808
809 *out = NULL;
810
811 msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
812 if (msg == NULL) return ASL_STATUS_NO_MEMORY;
813
814 msg->type = ASL_TYPE_MSG;
815 msg->count = 0;
816 if (pmsg->time != ASL_REF_NULL) msg->count++;
817 if (pmsg->host != ASL_REF_NULL) msg->count++;
818 if (pmsg->sender != ASL_REF_NULL) msg->count++;
819 if (pmsg->facility != ASL_REF_NULL) msg->count++;
820 if (pmsg->message != ASL_REF_NULL) msg->count++;
821 if (pmsg->level != ASL_INDEX_NULL) msg->count++;
822 if (pmsg->pid != -1) msg->count++;
823 if (pmsg->uid != -2) msg->count++;
824 if (pmsg->gid != -2) msg->count++;
825 if (pmsg->ruid != -1) msg->count++;
826 if (pmsg->rgid != -1) msg->count++;
827
828 msg->count += pmsg->kvcount / 2;
829
830 if (msg->count == 0)
831 {
832 free(msg);
833 return ASL_STATUS_INVALID_MESSAGE;
834 }
835
836 /* Message ID */
837 msg->count += 1;
838
839 msg->key = (char **)calloc(msg->count, sizeof(char *));
840 if (msg->key == NULL)
841 {
842 free(msg);
843 return ASL_STATUS_NO_MEMORY;
844 }
845
846 msg->val = (char **)calloc(msg->count, sizeof(char *));
847 if (msg->val == NULL)
848 {
849 free(msg->key);
850 free(msg);
851 return ASL_STATUS_NO_MEMORY;
852 }
853
854 n = 0;
855
856 /* Time */
857 if (pmsg->time != ASL_REF_NULL)
858 {
859 msg->key[n] = strdup(ASL_KEY_TIME);
860 if (msg->key[n] == NULL)
861 {
862 asl_free(msg);
863 return ASL_STATUS_NO_MEMORY;
864 }
865
866 asprintf(&(msg->val[n]), "%llu", pmsg->time);
867 if (msg->val[n] == NULL)
868 {
869 asl_free(msg);
870 return ASL_STATUS_NO_MEMORY;
871 }
872 n++;
873 }
874
875 /* Host */
876 if (pmsg->host != ASL_REF_NULL)
877 {
878 msg->key[n] = strdup(ASL_KEY_HOST);
879 if (msg->key[n] == NULL)
880 {
881 asl_free(msg);
882 return ASL_STATUS_NO_MEMORY;
883 }
884
885 status = string_fetch_sid(s, pmsg->host, &(msg->val[n]));
886 n++;
887 }
888
889 /* Sender */
890 if (pmsg->sender != ASL_REF_NULL)
891 {
892 msg->key[n] = strdup(ASL_KEY_SENDER);
893 if (msg->key[n] == NULL)
894 {
895 asl_free(msg);
896 return ASL_STATUS_NO_MEMORY;
897 }
898
899 status = string_fetch_sid(s, pmsg->sender, &(msg->val[n]));
900 n++;
901 }
902
903 /* Facility */
904 if (pmsg->facility != ASL_REF_NULL)
905 {
906 msg->key[n] = strdup(ASL_KEY_FACILITY);
907 if (msg->key[n] == NULL)
908 {
909 asl_free(msg);
910 return ASL_STATUS_NO_MEMORY;
911 }
912
913 status = string_fetch_sid(s, pmsg->facility, &(msg->val[n]));
914 n++;
915 }
916
917 /* Level */
918 if (pmsg->level != ASL_INDEX_NULL)
919 {
920 msg->key[n] = strdup(ASL_KEY_LEVEL);
921 if (msg->key[n] == NULL)
922 {
923 asl_free(msg);
924 return ASL_STATUS_NO_MEMORY;
925 }
926
927 asprintf(&(msg->val[n]), "%u", pmsg->level);
928 if (msg->val[n] == NULL)
929 {
930 asl_free(msg);
931 return ASL_STATUS_NO_MEMORY;
932 }
933 n++;
934 }
935
936 /* PID */
937 if (pmsg->pid != -1)
938 {
939 msg->key[n] = strdup(ASL_KEY_PID);
940 if (msg->key[n] == NULL)
941 {
942 asl_free(msg);
943 return ASL_STATUS_NO_MEMORY;
944 }
945
946 asprintf(&(msg->val[n]), "%d", pmsg->pid);
947 if (msg->val[n] == NULL)
948 {
949 asl_free(msg);
950 return ASL_STATUS_NO_MEMORY;
951 }
952 n++;
953 }
954
955 /* UID */
956 if (pmsg->uid != -2)
957 {
958 msg->key[n] = strdup(ASL_KEY_UID);
959 if (msg->key[n] == NULL)
960 {
961 asl_free(msg);
962 return ASL_STATUS_NO_MEMORY;
963 }
964
965 asprintf(&(msg->val[n]), "%d", pmsg->uid);
966 if (msg->val[n] == NULL)
967 {
968 asl_free(msg);
969 return ASL_STATUS_NO_MEMORY;
970 }
971 n++;
972 }
973
974 /* GID */
975 if (pmsg->gid != -2)
976 {
977 msg->key[n] = strdup(ASL_KEY_GID);
978 if (msg->key[n] == NULL)
979 {
980 asl_free(msg);
981 return ASL_STATUS_NO_MEMORY;
982 }
983
984 asprintf(&(msg->val[n]), "%d", pmsg->gid);
985 if (msg->val[n] == NULL)
986 {
987 asl_free(msg);
988 return ASL_STATUS_NO_MEMORY;
989 }
990 n++;
991 }
992
993 /* Message */
994 if (pmsg->message != ASL_REF_NULL)
995 {
996 msg->key[n] = strdup(ASL_KEY_MSG);
997 if (msg->key[n] == NULL)
998 {
999 asl_free(msg);
1000 return ASL_STATUS_NO_MEMORY;
1001 }
1002
1003 status = string_fetch_sid(s, pmsg->message, &(msg->val[n]));
1004 n++;
1005 }
1006
1007 /* ReadUID */
1008 if (pmsg->ruid != -1)
1009 {
1010 msg->key[n] = strdup(ASL_KEY_READ_UID);
1011 if (msg->key[n] == NULL)
1012 {
1013 asl_free(msg);
1014 return ASL_STATUS_NO_MEMORY;
1015 }
1016
1017 asprintf(&(msg->val[n]), "%d", pmsg->ruid);
1018 if (msg->val[n] == NULL)
1019 {
1020 asl_free(msg);
1021 return ASL_STATUS_NO_MEMORY;
1022 }
1023 n++;
1024 }
1025
1026 /* ReadGID */
1027 if (pmsg->rgid != -1)
1028 {
1029 msg->key[n] = strdup(ASL_KEY_READ_GID);
1030 if (msg->key[n] == NULL)
1031 {
1032 asl_free(msg);
1033 return ASL_STATUS_NO_MEMORY;
1034 }
1035
1036 asprintf(&(msg->val[n]), "%d", pmsg->rgid);
1037 if (msg->val[n] == NULL)
1038 {
1039 asl_free(msg);
1040 return ASL_STATUS_NO_MEMORY;
1041 }
1042 n++;
1043 }
1044
1045 /* Message ID */
1046 msg->key[n] = strdup(ASL_KEY_MSG_ID);
1047 if (msg->key[n] == NULL)
1048 {
1049 asl_free(msg);
1050 return ASL_STATUS_NO_MEMORY;
1051 }
1052
1053 asprintf(&(msg->val[n]), "%llu", pmsg->msgid);
1054 if (msg->val[n] == NULL)
1055 {
1056 asl_free(msg);
1057 return ASL_STATUS_NO_MEMORY;
1058 }
1059 n++;
1060
1061 /* Key - Value List */
1062 for (i = 0; i < pmsg->kvcount; i++)
1063 {
1064 key = NULL;
1065 status = string_fetch_sid(s, pmsg->kvlist[i++], &key);
1066 if (status != ASL_STATUS_OK)
1067 {
1068 if (key != NULL) free(key);
1069 continue;
1070 }
1071
1072 val = NULL;
1073 status = string_fetch_sid(s, pmsg->kvlist[i], &val);
1074 if (status != ASL_STATUS_OK)
1075 {
1076 if (key != NULL) free(key);
1077 if (val != NULL) free(val);
1078 continue;
1079 }
1080
1081 msg->key[n] = key;
1082 msg->val[n] = val;
1083 n++;
1084 }
1085
1086 *out = msg;
1087 return ASL_STATUS_OK;
1088}
1089
1090/*
1091 * Finds string either in the string cache or in the database
1092 */
1093static uint32_t
1094store_string_find(asl_legacy1_t *s, uint32_t hash, const char *str, uint32_t *index)
1095{
1096 uint32_t i, status;
1097 char *tmp;
1098
1099 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1100 if (str == NULL) return ASL_STATUS_INVALID_ARG;
1101 if (index == NULL) return ASL_STATUS_INVALID_ARG;
1102 if (s->slotlist == NULL) return ASL_STATUS_FAILED;
1103
1104 /* check the database */
1105 for (i = 0; i < s->slotlist_count; i++)
1106 {
1107 if ((s->slotlist[i].type != DB_TYPE_STRING) || (s->slotlist[i].hash != hash)) continue;
1108
1109 /* read the whole string */
1110 tmp = NULL;
1111 status = string_fetch_slot(s, s->slotlist[i].slot, &tmp);
1112 if (status != ASL_STATUS_OK) return status;
1113 if (tmp == NULL) return ASL_STATUS_FAILED;
1114
1115 status = strcmp(tmp, str);
1116 free(tmp);
1117 if (status != 0) continue;
1118
1119 /* Bingo! */
1120 *index = i;
1121 return ASL_STATUS_OK;
1122 }
1123
1124 return ASL_STATUS_FAILED;
1125}
1126
1127/*
1128 * Looks up a string ID number.
1129 */
1130static uint64_t
1131string_lookup(asl_legacy1_t *s, const char *str)
1132{
1133 uint32_t status, hash, index, slot, len;
1134 uint64_t nsid, sid;
1135 char *p;
1136 uint8_t inls;
1137
1138 if (s == NULL) return ASL_REF_NULL;
1139 if (str == NULL) return ASL_REF_NULL;
1140
1141 sid = ASL_REF_NULL;
1142 index = ASL_INDEX_NULL;
1143 slot = ASL_INDEX_NULL;
1144
1145 len = strlen(str);
1146 if (len < 8)
1147 {
1148 /* inline string */
1149 inls = len;
1150 inls |= 0x80;
1151
1152 nsid = 0;
1153 p = (char *)&nsid;
1154 memcpy(p, &inls, 1);
1155 memcpy(p + 1, str, len);
1156 sid = _asl_ntohq(nsid);
1157 return sid;
1158 }
1159
1160 hash = asl_core_string_hash(str, len);
1161
1162 /* check the database */
1163 status = store_string_find(s, hash, str, &index);
1164 if (status == ASL_STATUS_OK)
1165 {
1166 if (index == ASL_INDEX_NULL) return ASL_REF_NULL;
1167 return s->slotlist[index].xid;
1168 }
1169
1170 return ASL_REF_NULL;
1171}
1172
1173uint32_t
1174asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, asl_msg_t **msg)
1175{
1176 uint32_t status, slot;
1177 pmsg_t *pmsg;
1178
1179 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1180 if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG;
1181
1182 pmsg = NULL;
1183 slot = ASL_INDEX_NULL;
1184
1185 status = pmsg_fetch_by_id(s, msgid, &pmsg, &slot);
1186 if (status != ASL_STATUS_OK) return status;
1187 if (pmsg == NULL) return ASL_STATUS_FAILED;
1188
1189 status = msg_decode(s, pmsg, msg);
1190 free_pmsg(pmsg);
1191
1192 return status;
1193}
1194
1195static uint32_t
1196query_to_pmsg(asl_legacy1_t *s, asl_msg_t *q, pmsg_t **p)
1197{
1198 pmsg_t *out;
1199 uint32_t i, j;
1200 uint64_t ksid, vsid;
1201
1202 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1203 if (p == NULL) return ASL_STATUS_INVALID_ARG;
1204
1205 if (q == NULL) return Q_NULL;
1206 if (q->count == 0) return Q_NULL;
1207
1208 *p = NULL;
1209
1210 if (q->op != NULL)
1211 {
1212 for (i = 0; i < q->count; i++) if (q->op[i] != ASL_QUERY_OP_EQUAL) return Q_SLOW;
1213 }
1214
1215 out = (pmsg_t *)calloc(1, sizeof(pmsg_t));
1216 if (out == NULL) return ASL_STATUS_NO_MEMORY;
1217
1218 for (i = 0; i < q->count; i++)
1219 {
1220 if (q->key[i] == NULL) continue;
1221
1222 else if (!strcmp(q->key[i], ASL_KEY_TIME))
1223 {
1224 if (out->kselect & PMSG_SEL_TIME)
1225 {
1226 free_pmsg(out);
1227 return Q_SLOW;
1228 }
1229
1230 out->kselect |= PMSG_SEL_TIME;
1231 if (q->val[i] != NULL)
1232 {
1233 out->vselect |= PMSG_SEL_TIME;
1234 out->time = asl_parse_time(q->val[i]);
1235 }
1236 }
1237 else if (!strcmp(q->key[i], ASL_KEY_HOST))
1238 {
1239 if (out->kselect & PMSG_SEL_HOST)
1240 {
1241 free_pmsg(out);
1242 return Q_SLOW;
1243 }
1244
1245 out->kselect |= PMSG_SEL_HOST;
1246 if (q->val[i] != NULL)
1247 {
1248 out->vselect |= PMSG_SEL_HOST;
1249 out->host = string_lookup(s, q->val[i]);
1250 if (out->host == ASL_REF_NULL)
1251 {
1252 free_pmsg(out);
1253 return Q_FAIL;
1254 }
1255 }
1256 }
1257 else if (!strcmp(q->key[i], ASL_KEY_SENDER))
1258 {
1259 if (out->kselect & PMSG_SEL_SENDER)
1260 {
1261 free_pmsg(out);
1262 return Q_SLOW;
1263 }
1264
1265 out->kselect |= PMSG_SEL_SENDER;
1266 if (q->val[i] != NULL)
1267 {
1268 out->vselect |= PMSG_SEL_SENDER;
1269 out->sender = string_lookup(s, q->val[i]);
1270 if (out->sender == ASL_REF_NULL)
1271 {
1272 free_pmsg(out);
1273 return Q_FAIL;
1274 }
1275 }
1276 }
1277 else if (!strcmp(q->key[i], ASL_KEY_PID))
1278 {
1279 if (out->kselect & PMSG_SEL_PID)
1280 {
1281 free_pmsg(out);
1282 return Q_SLOW;
1283 }
1284
1285 out->kselect |= PMSG_SEL_PID;
1286 if (q->val[i] != NULL)
1287 {
1288 out->vselect |= PMSG_SEL_PID;
1289 out->pid = atoi(q->val[i]);
1290 }
1291 }
1292 else if (!strcmp(q->key[i], ASL_KEY_UID))
1293 {
1294 if (out->kselect & PMSG_SEL_UID)
1295 {
1296 free_pmsg(out);
1297 return Q_SLOW;
1298 }
1299
1300 out->kselect |= PMSG_SEL_UID;
1301 if (q->val[i] != NULL)
1302 {
1303 out->vselect |= PMSG_SEL_UID;
1304 out->uid = atoi(q->val[i]);
1305 }
1306 }
1307 else if (!strcmp(q->key[i], ASL_KEY_GID))
1308 {
1309 if (out->kselect & PMSG_SEL_GID)
1310 {
1311 free_pmsg(out);
1312 return Q_SLOW;
1313 }
1314
1315 out->kselect |= PMSG_SEL_GID;
1316 if (q->val[i] != NULL)
1317 {
1318 out->vselect |= PMSG_SEL_GID;
1319 out->gid = atoi(q->val[i]);
1320 }
1321 }
1322 else if (!strcmp(q->key[i], ASL_KEY_LEVEL))
1323 {
1324 if (out->kselect & PMSG_SEL_LEVEL)
1325 {
1326 free_pmsg(out);
1327 return Q_SLOW;
1328 }
1329
1330 out->kselect |= PMSG_SEL_LEVEL;
1331 if (q->val[i] != NULL)
1332 {
1333 out->vselect |= PMSG_SEL_LEVEL;
1334 out->level = atoi(q->val[i]);
1335 }
1336 }
1337 else if (!strcmp(q->key[i], ASL_KEY_MSG))
1338 {
1339 if (out->kselect & PMSG_SEL_MESSAGE)
1340 {
1341 free_pmsg(out);
1342 return Q_SLOW;
1343 }
1344
1345 out->kselect |= PMSG_SEL_MESSAGE;
1346 if (q->val[i] != NULL)
1347 {
1348 out->vselect |= PMSG_SEL_MESSAGE;
1349 out->message = string_lookup(s, q->val[i]);
1350 if (out->message == ASL_REF_NULL)
1351 {
1352 free_pmsg(out);
1353 return Q_FAIL;
1354 }
1355 }
1356 }
1357 else if (!strcmp(q->key[i], ASL_KEY_FACILITY))
1358 {
1359 if (out->kselect & PMSG_SEL_FACILITY)
1360 {
1361 free_pmsg(out);
1362 return Q_SLOW;
1363 }
1364
1365 out->kselect |= PMSG_SEL_FACILITY;
1366 if (q->val[i] != NULL)
1367 {
1368 out->vselect |= PMSG_SEL_FACILITY;
1369 out->facility = string_lookup(s, q->val[i]);
1370 if (out->facility == ASL_REF_NULL)
1371 {
1372 free_pmsg(out);
1373 return Q_FAIL;
1374 }
1375 }
1376 }
1377 else if (!strcmp(q->key[i], ASL_KEY_READ_UID))
1378 {
1379 if (out->kselect & PMSG_SEL_RUID)
1380 {
1381 free_pmsg(out);
1382 return Q_SLOW;
1383 }
1384
1385 out->kselect |= PMSG_SEL_RUID;
1386 if (q->val[i] != NULL)
1387 {
1388 out->vselect |= PMSG_SEL_RUID;
1389 out->ruid = atoi(q->val[i]);
1390 }
1391 }
1392 else if (!strcmp(q->key[i], ASL_KEY_READ_GID))
1393 {
1394 if (out->kselect & PMSG_SEL_RGID)
1395 {
1396 free_pmsg(out);
1397 return Q_SLOW;
1398 }
1399
1400 out->kselect |= PMSG_SEL_RGID;
1401 if (q->val[i] != NULL)
1402 {
1403 out->vselect |= PMSG_SEL_RGID;
1404 out->rgid = atoi(q->val[i]);
1405 }
1406 }
1407 else
1408 {
1409 ksid = string_lookup(s, q->key[i]);
1410 if (ksid == ASL_REF_NULL)
1411 {
1412 free_pmsg(out);
1413 return Q_FAIL;
1414 }
1415
1416 for (j = 0; j < out->kvcount; j += 2)
1417 {
1418 if (out->kvlist[j] == ksid)
1419 {
1420 free_pmsg(out);
1421 return Q_SLOW;
1422 }
1423 }
1424
1425 vsid = ASL_REF_NULL;
1426 if (q->val[i] != NULL)
1427 {
1428 vsid = string_lookup(s, q->val[i]);
1429 if (ksid == ASL_REF_NULL)
1430 {
1431 free_pmsg(out);
1432 return Q_FAIL;
1433 }
1434 }
1435
1436 if (out->kvcount == 0)
1437 {
1438 out->kvlist = (uint64_t *)calloc(2, sizeof(uint64_t));
1439 }
1440 else
1441 {
1442 out->kvlist = (uint64_t *)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(uint64_t));
1443 }
1444
1445 if (out->kvlist == NULL)
1446 {
1447 free_pmsg(out);
1448 return ASL_STATUS_NO_MEMORY;
1449 }
1450
1451 out->kvlist[out->kvcount++] = ksid;
1452 out->kvlist[out->kvcount++] = vsid;
1453 }
1454 }
1455
1456 *p = out;
1457 return Q_FAST;
1458}
1459
1460static uint32_t
1461msg_match(asl_legacy1_t *s, uint32_t qtype, pmsg_t *qp, asl_msg_t *q, uint32_t slot, pmsg_t **iopm, asl_msg_t **iomsg, asl_msg_list_t **res, uint32_t *didmatch)
1462{
1463 uint32_t status, what;
1464
1465 *didmatch = 0;
1466
1467 if (qtype == Q_FAIL) return ASL_STATUS_OK;
1468
1469 if (qtype == Q_NULL)
1470 {
1471 if (*iopm == NULL)
1472 {
1473 status = pmsg_fetch(s, slot, PMSG_FETCH_ALL, iopm);
1474 if (status != ASL_STATUS_OK) return status;
1475 if (*iopm == NULL) return ASL_STATUS_FAILED;
1476 }
1477 }
1478 else if (qtype == Q_FAST)
1479 {
1480 if (qp == NULL) return ASL_STATUS_INVALID_ARG;
1481
1482 what = PMSG_FETCH_STD;
1483 if (qp->kvcount > 0) what = PMSG_FETCH_ALL;
1484
1485 if (*iopm == NULL)
1486 {
1487 status = pmsg_fetch(s, slot, what, iopm);
1488 if (status != ASL_STATUS_OK) return status;
1489 if (*iopm == NULL) return ASL_STATUS_FAILED;
1490 }
1491
1492 status = pmsg_match(s, qp, *iopm);
1493 if (status == 1)
1494 {
1495 if ((what == PMSG_FETCH_STD) && ((*iopm)->next != 0) && ((*iopm)->kvcount == 0))
1496 {
1497 status = pmsg_fetch(s, slot, PMSG_FETCH_KV, iopm);
1498 if (status != ASL_STATUS_OK) return status;
1499 if (*iopm == NULL) return ASL_STATUS_FAILED;
1500 }
1501 }
1502 else return ASL_STATUS_OK;
1503 }
1504 else if (qtype == Q_SLOW)
1505 {
1506 if (*iomsg == NULL)
1507 {
1508 if (*iopm == NULL)
1509 {
1510 status = pmsg_fetch(s, slot, PMSG_FETCH_ALL, iopm);
1511 if (status != ASL_STATUS_OK) return status;
1512 if (*iopm == NULL) return ASL_STATUS_FAILED;
1513 }
1514
1515 status = msg_decode(s, *iopm, iomsg);
1516 if (status == ASL_STATUS_INVALID_MESSAGE) return ASL_STATUS_OK;
1517 if (status != ASL_STATUS_OK) return status;
1518 if (*iomsg == NULL) return ASL_STATUS_FAILED;
1519 }
1520
1521 status = 0;
1522 if (asl_msg_cmp(q, *iomsg) != 0) status = 1;
1523 if (status == 0) return ASL_STATUS_OK;
1524 }
1525
1526 *didmatch = 1;
1527
1528 if (res == NULL) return ASL_STATUS_OK;
1529
1530 if (*iomsg == NULL)
1531 {
1532 status = msg_decode(s, *iopm, iomsg);
1533 if (status == ASL_STATUS_INVALID_MESSAGE)
1534 {
1535 *didmatch = 0;
1536 return ASL_STATUS_OK;
1537 }
1538
1539 if (status != ASL_STATUS_OK) return status;
1540 }
1541
1542 if ((*res)->count == 0) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1543 else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, (1 + (*res)->count) * sizeof(asl_msg_t *));
1544 if ((*res)->msg == NULL) return ASL_STATUS_NO_MEMORY;
1545
1546 (*res)->msg[(*res)->count++] = *iomsg;
1547
1548 return ASL_STATUS_OK;
1549}
1550
1551static uint32_t
1552next_search_slot(asl_legacy1_t *s, uint32_t last_si, int32_t direction)
1553{
1554 uint32_t i;
1555
1556 if (direction >= 0)
1557 {
1558 for (i = last_si + 1; i < s->slotlist_count; i++)
1559 {
1560 if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i;
1561 }
1562
1563 return ASL_INDEX_NULL;
1564 }
1565
1566 if (last_si == 0) return ASL_INDEX_NULL;
1567 if (last_si > s->slotlist_count) return ASL_INDEX_NULL;
1568
1569 for (i = last_si - 1; i > 0; i--)
1570 {
1571 if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i;
1572 }
1573
1574 if (s->slotlist[0].type == DB_TYPE_MESSAGE) return 0;
1575
1576 return ASL_INDEX_NULL;
1577}
1578
1579static uint32_t
1580query_list_to_pmsg_list(asl_legacy1_t *s, asl_msg_list_t *query, uint32_t *match, pmsg_t ***qp, uint32_t **qtype, uint32_t *count)
1581{
1582 pmsg_t **outp, *pm;
1583 uint32_t i, j, *outt;
1584 *match = 0;
1585 *qp = NULL;
1586 *qtype = 0;
1587 *count = 0;
1588
1589 if (query == NULL) return ASL_STATUS_OK;
1590 if (match == NULL) return ASL_STATUS_INVALID_ARG;
1591 if (qp == NULL) return ASL_STATUS_INVALID_ARG;
1592 if (qtype == NULL) return ASL_STATUS_OK;
1593 if (query->msg == NULL) return ASL_STATUS_OK;
1594 if (query->count == 0) return ASL_STATUS_OK;
1595
1596 outp = (pmsg_t **)calloc(query->count, sizeof(pmsg_t *));
1597 if (outp == NULL) return ASL_STATUS_NO_MEMORY;
1598
1599 outt = (uint32_t *)calloc(query->count, sizeof(uint32_t));
1600 if (outt == NULL)
1601 {
1602 free(outp);
1603 return ASL_STATUS_NO_MEMORY;
1604 }
1605
1606 *match = 1;
1607
1608 for (i = 0; i < query->count; i++)
1609 {
1610 pm = NULL;
1611 outt[i] = query_to_pmsg(s, query->msg[i], &pm);
1612 if (outt[i] <= ASL_STATUS_FAILED)
1613 {
1614 if (pm != NULL) free_pmsg(pm);
1615 for (j = 0; j < i; j++) free_pmsg(outp[j]);
1616 free(outp);
1617 free(outt);
1618 return ASL_STATUS_NO_MEMORY;
1619 }
1620
1621 outp[i] = pm;
1622 }
1623
1624 *count = query->count;
1625 *qp = outp;
1626 *qtype = outt;
1627 return ASL_STATUS_OK;
1628}
1629
1630static void
1631match_worker_cleanup(pmsg_t **ql, uint32_t *qt, uint32_t n, asl_msg_list_t **res)
1632{
1633 uint32_t i;
1634
1635 if (ql != NULL)
1636 {
1637 for (i = 0; i < n; i++) free_pmsg(ql[i]);
1638 free(ql);
1639 }
1640
1641 if (qt != NULL) free(qt);
1642
1643 if (res != NULL)
1644 {
1645 for (i = 0; i < (*res)->count; i++) asl_free((*res)->msg[i]);
1646 free(*res);
1647 }
1648}
1649
1650/*
1651 * Input to asl_legacy1_match is a list of queries.
1652 * A record in the store matches if it matches any query (i.e. query list is "OR"ed)
1653 *
1654 * If counting up (direction is positive) find first record with ID > start_id.
1655 * Else if counting down (direction is negative) find first record with ID < start_id.
1656 *
1657 * Set match flag on.
1658 * If any query is NULL, set match flog off (skips matching below).
1659 * Else if all queries only check "standard" keys, set std flag to on.
1660 *
1661 * If a query only tests equality, convert it to a pmsg_t. The conversion routine
1662 * checks for string values that are NOT in the database. If a string is not found,
1663 * the conversion fails and the query is markes as "never matches". Otherwise,
1664 * the query is marked "fast".
1665 *
1666 * If all queries are marked as "never matches", return NULL.
1667 *
1668 * match loop:
1669 * fetch record (with std flag)
1670 * if match flag is off, decode record and add it to result.
1671 * else for each query:
1672 * if query is NULL (shouldn't happen) decode record and add it to result. Return to match loop.
1673 * else if query never matches, ignore it.
1674 * else if query is fast, use pmsg_match. If it succeeds, decode record and add it to result. Return to match loop.
1675 * else decode record and use asl_cmp. If it succeeds, add record to result. Return to match loop.
1676 *
1677 * return results.
1678 */
1679static uint32_t
1680match_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)
1681{
1682 uint32_t mx, si, slot, i, qcount, match, didmatch, status, *qtype;
1683 uint64_t xid;
1684 pmsg_t **qp, *iopmsg;
1685 asl_msg_t *iomsg;
1686
1687 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1688 if ((res == NULL) && (idlist == NULL)) return ASL_STATUS_INVALID_ARG;
1689 if (last_id == NULL) return ASL_STATUS_INVALID_ARG;
1690 if (idcount == NULL) return ASL_STATUS_INVALID_ARG;
1691
1692 if (res != NULL) *res = NULL;
1693 if (idlist != NULL) *idlist = NULL;
1694
1695 mx = 0;
1696
1697 if (direction < 0) direction = -1;
1698 else direction = 1;
1699
1700 si = ASL_INDEX_NULL;
1701 if ((direction == -1) && (start_id == ASL_REF_NULL)) si = s->slotlist_count;
1702 else si = slotlist_find(s, start_id, direction);
1703
1704 si = next_search_slot(s, si, direction);
1705 if (si == ASL_INDEX_NULL) return ASL_STATUS_OK;
1706 if (si >= s->slotlist_count) return ASL_STATUS_FAILED;
1707
1708 slot = s->slotlist[si].slot;
1709
1710 status = query_list_to_pmsg_list(s, query, &match, &qp, &qtype, &qcount);
1711 if (status != ASL_STATUS_OK) return status;
1712
1713 /*
1714 * initialize result list if we've been asked to return messages
1715 */
1716 if (res != NULL)
1717 {
1718 *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
1719 if (*res == NULL)
1720 {
1721 match_worker_cleanup(qp, qtype, qcount, NULL);
1722 return ASL_STATUS_NO_MEMORY;
1723 }
1724 }
1725
1726 /*
1727 * loop through records
1728 */
1729 *idcount = 0;
1730 while ((count == 0) || (*idcount < count))
1731 {
1732 if (si == ASL_INDEX_NULL) break;
1733 if (si >= s->slotlist_count) break;
1734
1735 slot = s->slotlist[si].slot;
1736 xid = s->slotlist[si].xid;
1737
1738 *last_id = xid;
1739
1740 iopmsg = NULL;
1741 iomsg = NULL;
1742
1743 didmatch = 0;
1744 if (match == 0)
1745 {
1746 status = msg_match(s, Q_NULL, NULL, NULL, slot, &iopmsg, &iomsg, res, &didmatch);
1747 free_pmsg(iopmsg);
1748 if (didmatch == 0)
1749 {
1750 asl_free(iomsg);
1751 iomsg = NULL;
1752 }
1753 else
1754 {
1755 if (idlist != NULL)
1756 {
1757 if (*idlist == NULL) *idlist = (uint64_t *)calloc(1, sizeof(uint64_t));
1758 else *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t));
1759 if (*idlist == NULL) status = ASL_STATUS_NO_MEMORY;
1760 else (*idlist)[*idcount] = xid;
1761 }
1762
1763 (*idcount)++;
1764 }
1765
1766 if (status != ASL_STATUS_OK)
1767 {
1768 match_worker_cleanup(qp, qtype, qcount, res);
1769 return status;
1770 }
1771 }
1772 else
1773 {
1774 for (i = 0; i < qcount; i++)
1775 {
1776 status = msg_match(s, qtype[i], qp[i], query->msg[i], slot, &iopmsg, &iomsg, res, &didmatch);
1777 if (status != ASL_STATUS_OK)
1778 {
1779 free_pmsg(iopmsg);
1780 asl_free(iomsg);
1781 match_worker_cleanup(qp, qtype, qcount, res);
1782 return status;
1783 }
1784
1785 if (didmatch == 1)
1786 {
1787 if (idlist != NULL)
1788 {
1789 if (*idlist == NULL) *idlist = (uint64_t *)calloc(1, sizeof(uint64_t));
1790 else *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t));
1791 if (*idlist == NULL)
1792 {
1793 match_worker_cleanup(qp, qtype, qcount, res);
1794 return ASL_STATUS_NO_MEMORY;
1795 }
1796
1797 (*idlist)[*idcount] = xid;
1798 }
1799
1800 (*idcount)++;
1801 break;
1802 }
1803 }
1804
1805 free_pmsg(iopmsg);
1806 if ((didmatch == 0) || (res == NULL)) asl_free(iomsg);
1807 }
1808
1809 si = next_search_slot(s, si, direction);
1810 }
1811
1812 match_worker_cleanup(qp, qtype, qcount, NULL);
1813 return status;
1814}
1815
1816uint32_t
1817asl_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)
1818{
1819 uint32_t idcount;
1820
1821 idcount = 0;
1822 return match_worker(s, query, res, last_id, NULL, &idcount, start_id, count, direction);
1823}