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