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 time_t asl_parse_time(const char *str); 87extern 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 96static 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 118static 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 140static 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 149static 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 158static 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 */ 178static int 179slot_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 */ 207static uint32_t 208slotlist_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 239static uint32_t 240slotlist_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 302uint32_t 303asl_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 354uint32_t 355asl_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 366static uint32_t 367string_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 447static uint32_t 448string_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 485static uint32_t 486asl_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 507static uint64_t 508asl_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 524static uint64_t 525asl_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 548static uint32_t 549msg_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 645uint32_t 646asl_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 665static uint32_t 666next_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 693static void 694match_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 */ 728static uint32_t 729match_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 829uint32_t 830asl_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} 837