1/* 2 * Copyright (c) 2009-2012 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 24#include <string.h> 25#include <stdint.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <ctype.h> 29#include <unistd.h> 30#include <stdarg.h> 31#include <regex.h> 32#include <syslog.h> 33#include <notify.h> 34#include <errno.h> 35#include <time.h> 36#include <sys/time.h> 37#include <asl.h> 38#include <asl_object.h> 39#include <asl_private.h> 40#include <asl_core.h> 41#include <sys/types.h> 42#include <libkern/OSAtomic.h> 43#include <asl_msg.h> 44#include <asl_msg_list.h> 45 46#define TOKEN_NULL 0 47#define TOKEN_OPEN 1 48#define TOKEN_CLOSE 2 49#define TOKEN_WORD 3 50#define TOKEN_INT 4 51 52#define MFMT_RAW 0 53#define MFMT_STD 1 54#define MFMT_BSD 2 55#define MFMT_XML 3 56#define MFMT_STR 4 57#define MFMT_MSG 5 58 59#define SEC_PER_HOUR 3600 60 61#define PAGE_OBJECT 1 62 63#define forever for(;;) 64 65#define streq(A, B) (strcmp(A, B) == 0) 66#define streq_len(A, B, C) (strncmp(A, B, C) == 0) 67#define strneq(A, B) (strcmp(A, B) != 0) 68#define strcaseeq(A, B) (strcasecmp(A, B) == 0) 69#define strcaseneq(A, B) (strcasecmp(A, B) != 0) 70 71#ifndef ASL_QUERY_OP_FALSE 72#define ASL_QUERY_OP_FALSE 0 73#endif 74 75#define AUX_0_TIME 0x00000001 76#define AUX_0_TIME_NSEC 0x00000002 77#define AUX_0_HOST 0x00000004 78#define AUX_0_SENDER 0x00000008 79#define AUX_0_FACILITY 0x00000010 80#define AUX_0_PID 0x00000020 81#define AUX_0_UID 0x00000040 82#define AUX_0_GID 0x00000080 83#define AUX_0_MSG 0x00000100 84#define AUX_0_OPTION 0x00000200 85#define AUX_0_LEVEL 0x00000400 86 87/* from asl_util.c */ 88int asl_is_utf8(const char *str); 89uint8_t *asl_b64_encode(const uint8_t *buf, size_t len); 90 91void _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg); 92 93#pragma mark - 94#pragma mark standard message keys 95 96static const char *ASLStandardKey[] = 97{ 98 ASL_KEY_TIME, 99 ASL_KEY_TIME_NSEC, 100 ASL_KEY_HOST, 101 ASL_KEY_SENDER, 102 ASL_KEY_FACILITY, 103 ASL_KEY_PID, 104 ASL_KEY_UID, 105 ASL_KEY_GID, 106 ASL_KEY_LEVEL, 107 ASL_KEY_MSG, 108 ASL_KEY_READ_UID, 109 ASL_KEY_READ_GID, 110 ASL_KEY_SESSION, 111 ASL_KEY_REF_PID, 112 ASL_KEY_REF_PROC, 113 ASL_KEY_MSG_ID, 114 ASL_KEY_EXPIRE_TIME, 115 ASL_KEY_OPTION, 116 ASL_KEY_FREE_NOTE 117}; 118 119static const char *MTStandardKey[] = 120{ 121 "com.apple.message.domain", 122 "com.apple.message.domain_scope", 123 "com.apple.message.result", 124 "com.apple.message.signature", 125 "com.apple.message.signature2", 126 "com.apple.message.signature3", 127 "com.apple.message.success", 128 "com.apple.message.uuid", 129 "com.apple.message.value", 130 "com.apple.message.value2", 131 "com.apple.message.value3", 132 "com.apple.message.value4", 133 "com.apple.message.value5" 134}; 135 136static uint16_t 137_asl_msg_std_key(const char *s, uint32_t len) 138{ 139 if ((len > 18) && (streq_len(s, "com.apple.message.", 18))) 140 { 141 if (streq(s + 18, "domain")) return ASL_MT_KEY_DOMAIN; 142 else if (streq(s + 18, "domain_scope")) return ASL_MT_KEY_SCOPE; 143 else if (streq(s + 18, "result")) return ASL_MT_KEY_RESULT; 144 else if (streq(s + 18, "signature")) return ASL_MT_KEY_SIG; 145 else if (streq(s + 18, "signature2")) return ASL_MT_KEY_SIG2; 146 else if (streq(s + 18, "signature3")) return ASL_MT_KEY_SIG3; 147 else if (streq(s + 18, "success")) return ASL_MT_KEY_SUCCESS; 148 else if (streq(s + 18, "uuid")) return ASL_MT_KEY_UUID; 149 else if (streq(s + 18, "value")) return ASL_MT_KEY_VAL; 150 else if (streq(s + 18, "value2")) return ASL_MT_KEY_VAL2; 151 else if (streq(s + 18, "value3")) return ASL_MT_KEY_VAL3; 152 else if (streq(s + 18, "value4")) return ASL_MT_KEY_VAL4; 153 else if (streq(s + 18, "value5")) return ASL_MT_KEY_VAL5; 154 155 return 0; 156 } 157 158 switch (len) 159 { 160 case 3: 161 { 162 if streq(s, ASL_KEY_PID) return ASL_STD_KEY_PID; 163 else if streq(s, ASL_KEY_UID) return ASL_STD_KEY_UID; 164 else if streq(s, ASL_KEY_GID) return ASL_STD_KEY_GID; 165 } 166 case 4: 167 { 168 if streq(s, ASL_KEY_TIME) return ASL_STD_KEY_TIME; 169 else if streq(s, ASL_KEY_HOST) return ASL_STD_KEY_HOST; 170 } 171 case 5: 172 { 173 if streq(s, ASL_KEY_LEVEL) return ASL_STD_KEY_LEVEL; 174 } 175 case 6: 176 { 177 if streq(s, ASL_KEY_SENDER) return ASL_STD_KEY_SENDER; 178 else if streq(s, ASL_KEY_REF_PID) return ASL_STD_KEY_REF_PID; 179 } 180 case 7: 181 { 182 if streq(s, ASL_KEY_MSG) return ASL_STD_KEY_MESSAGE; 183 else if streq(s, ASL_KEY_SESSION) return ASL_STD_KEY_SESSION; 184 else if streq(s, ASL_KEY_READ_UID) return ASL_STD_KEY_READ_UID; 185 else if streq(s, ASL_KEY_READ_GID) return ASL_STD_KEY_READ_GID; 186 else if streq(s, ASL_KEY_REF_PROC) return ASL_STD_KEY_REF_PROC; 187 } 188 case 8: 189 { 190 if streq(s, ASL_KEY_FACILITY) return ASL_STD_KEY_FACILITY; 191 } 192 case 9: 193 { 194 if streq(s, ASL_KEY_OPTION) return ASL_STD_KEY_OPTION; 195 } 196 case 11: 197 { 198 if streq(s, ASL_KEY_TIME_NSEC) return ASL_STD_KEY_NANO; 199 } 200 case 12: 201 { 202 if streq(s, ASL_KEY_MSG_ID) return ASL_STD_KEY_MSG_ID; 203 } 204 case 13: 205 { 206 if streq(s, ASL_KEY_EXPIRE_TIME) return ASL_STD_KEY_EXPIRE; 207 } 208 case 14: 209 { 210 if streq(s, ASL_KEY_FREE_NOTE) return ASL_STD_KEY_FREE_NOTE; 211 } 212 default: 213 { 214 return 0; 215 } 216 } 217 218 return 0; 219} 220 221#pragma mark - 222#pragma mark asl_msg 223 224static asl_msg_t * 225_asl_msg_make_page(void) 226{ 227 int i; 228 asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); 229 230 if (out == NULL) return NULL; 231 232 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) 233 { 234 out->key[i] = ASL_MSG_SLOT_FREE; 235 out->val[i] = ASL_MSG_SLOT_FREE; 236 } 237 238 out->mem_size = sizeof(asl_msg_t); 239 240 return out; 241} 242 243asl_msg_t * 244asl_msg_retain(asl_msg_t *msg) 245{ 246 if (msg == NULL) return NULL; 247 asl_retain((asl_object_t)msg); 248 return msg; 249} 250 251void 252asl_msg_release(asl_msg_t *msg) 253{ 254 if (msg == NULL) return; 255 asl_release((asl_object_t)msg); 256} 257 258static const char * 259_asl_msg_slot_key(asl_msg_t *page, uint32_t slot) 260{ 261 const char *out; 262 uint16_t x; 263 264 if (page == NULL) return NULL; 265 if (slot >= ASL_MSG_PAGE_SLOTS) return NULL; 266 if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL; 267 268 switch (page->key[slot] & ASL_MSG_KV_MASK) 269 { 270 case ASL_MSG_KV_INLINE: 271 { 272 return page->data + page->key[slot]; 273 } 274 case ASL_MSG_KV_DICT: 275 { 276 if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST)) 277 { 278 x = page->key[slot] - ASL_STD_KEY_BASE - 1; 279 return ASLStandardKey[x]; 280 } 281 else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST)) 282 { 283 x = page->key[slot] - ASL_MT_KEY_BASE - 1; 284 return MTStandardKey[x]; 285 } 286 287 return NULL; 288 } 289 case ASL_MSG_KV_EXTERN: 290 { 291 x = page->key[slot] & ASL_MSG_OFFSET_MASK; 292 memcpy(&out, page->data + x, sizeof(char *)); 293 return out; 294 } 295 } 296 297 return NULL; 298} 299 300static const char * 301_asl_msg_slot_val(asl_msg_t *page, uint32_t slot) 302{ 303 const char *out; 304 uint16_t x, type; 305 306 if (page == NULL) return NULL; 307 if (slot >= ASL_MSG_PAGE_SLOTS) return NULL; 308 309 if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL; 310 311 type = page->val[slot] & ASL_MSG_KV_MASK; 312 313 if (type == ASL_MSG_KV_INLINE) 314 { 315 return page->data + page->val[slot]; 316 } 317 else if (type == ASL_MSG_KV_EXTERN) 318 { 319 x = page->val[slot] & ASL_MSG_OFFSET_MASK; 320 memcpy(&out, page->data + x, sizeof(char *)); 321 return out; 322 } 323 324 return NULL; 325} 326 327/* 328 * asl_new: create a new log message. 329 */ 330asl_msg_t * 331asl_msg_new(uint32_t type) 332{ 333 asl_msg_t *out; 334 335 out = _asl_msg_make_page(); 336 if (out == NULL) return NULL; 337 338 out->asl_type = type; 339 out->refcount = 1; 340 341 return out; 342} 343 344static void 345_asl_msg_free_page(asl_msg_t *page) 346{ 347 uint32_t i; 348 char *p; 349 350 if (page == NULL) return; 351 352 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) 353 { 354 if (page->key[i] == ASL_STD_KEY_FREE_NOTE) 355 { 356 const char *x = _asl_msg_slot_val(page, i); 357 if (x != NULL) notify_post(x); 358 } 359 360 if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 361 { 362 memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 363 free(p); 364 } 365 366 if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 367 { 368 memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 369 free(p); 370 } 371 } 372 373 free(page); 374} 375 376uint32_t 377asl_msg_type(asl_msg_t *msg) 378{ 379 if (msg == NULL) return 0; 380 return msg->asl_type; 381} 382 383uint32_t 384asl_msg_count(asl_msg_t *msg) 385{ 386 uint32_t total; 387 388 total = 0; 389 390 for (; msg != NULL; msg = msg->next) total += msg->count; 391 return total; 392} 393 394static void 395_asl_msg_dump_kv(FILE *f, asl_msg_t *msg, uint16_t x) 396{ 397 if (x == ASL_MSG_SLOT_FREE) 398 { 399 fprintf(f, "-free-"); 400 return; 401 } 402 403 if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT) 404 { 405 switch (x) 406 { 407 case ASL_STD_KEY_TIME: fprintf(f, "(dict: Time)"); return; 408 case ASL_STD_KEY_NANO: fprintf(f, "(dict: Nano)"); return; 409 case ASL_STD_KEY_HOST: fprintf(f, "(dict: Host)"); return; 410 case ASL_STD_KEY_SENDER: fprintf(f, "(dict: Sender)"); return; 411 case ASL_STD_KEY_FACILITY: fprintf(f, "(dict: Facility)"); return; 412 case ASL_STD_KEY_PID: fprintf(f, "(dict: PID)"); return; 413 case ASL_STD_KEY_UID: fprintf(f, "(dict: UID)"); return; 414 case ASL_STD_KEY_GID: fprintf(f, "(dict: GID)"); return; 415 case ASL_STD_KEY_LEVEL: fprintf(f, "(dict: Level)"); return; 416 case ASL_STD_KEY_MESSAGE: fprintf(f, "(dict: Message)"); return; 417 case ASL_STD_KEY_READ_UID: fprintf(f, "(dict: ReadUID)"); return; 418 case ASL_STD_KEY_READ_GID: fprintf(f, "(dict: ReadGID)"); return; 419 case ASL_STD_KEY_SESSION: fprintf(f, "(dict: Session)"); return; 420 case ASL_STD_KEY_REF_PID: fprintf(f, "(dict: PID)"); return; 421 case ASL_STD_KEY_REF_PROC: fprintf(f, "(dict: RefProc)"); return; 422 case ASL_STD_KEY_MSG_ID: fprintf(f, "(dict: ASLMessageID)"); return; 423 case ASL_STD_KEY_EXPIRE: fprintf(f, "(dict: Expire)"); return; 424 case ASL_STD_KEY_OPTION: fprintf(f, "(dict: ASLOption)"); return; 425 case ASL_MT_KEY_DOMAIN: fprintf(f, "(dict: com.apple.message.domain)"); return; 426 case ASL_MT_KEY_SCOPE: fprintf(f, "(dict: com.apple.message.domain_scope)"); return; 427 case ASL_MT_KEY_RESULT: fprintf(f, "(dict: com.apple.message.result)"); return; 428 case ASL_MT_KEY_SIG: fprintf(f, "(dict: com.apple.message.signature)"); return; 429 case ASL_MT_KEY_SIG2: fprintf(f, "(dict: com.apple.message.signature2)"); return; 430 case ASL_MT_KEY_SIG3: fprintf(f, "(dict: com.apple.message.signature3)"); return; 431 case ASL_MT_KEY_SUCCESS: fprintf(f, "(dict: com.apple.message.success)"); return; 432 case ASL_MT_KEY_UUID: fprintf(f, "(dict: com.apple.message.uuid)"); return; 433 case ASL_MT_KEY_VAL: fprintf(f, "(dict: com.apple.message.value)"); return; 434 case ASL_MT_KEY_VAL2: fprintf(f, "(dict: com.apple.message.value2)"); return; 435 case ASL_MT_KEY_VAL3: fprintf(f, "(dict: com.apple.message.value3)"); return; 436 case ASL_MT_KEY_VAL4: fprintf(f, "(dict: com.apple.message.value4)"); return; 437 case ASL_MT_KEY_VAL5: fprintf(f, "(dict: com.apple.message.value5)"); return; 438 } 439 440 fprintf(f, "(dict: -unknown-)"); 441 return; 442 } 443 444 if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 445 { 446 const char *c; 447 size_t z = x & ASL_MSG_OFFSET_MASK; 448 memcpy(&c, msg->data + z, sizeof(char *)); 449 fprintf(f, "(extern: %s)", c); 450 return; 451 } 452 453 fprintf(f, "%s", msg->data + x); 454} 455 456void 457_asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) 458{ 459 int i, page1 = 1; 460 461 if (f == NULL) return; 462 if (msg == NULL) 463 { 464 fprintf(f, "asl_msg %s: NULL\n", comment); 465 return; 466 } 467 468 while (msg != NULL) 469 { 470 if (page1 == 1) 471 { 472 fprintf(f, "asl_msg %s: %p\n", comment, msg); 473 fprintf(f, " refcount: %u\n", msg->refcount); 474 fprintf(f, " asl_type: %u\n", msg->asl_type); 475 page1 = 0; 476 } 477 else 478 { 479 fprintf(f, " page: %p\n", msg); 480 } 481 482 fprintf(f, " count: %u\n", msg->count); 483 fprintf(f, " data_size: %u\n", msg->data_size); 484 fprintf(f, " mem_size: %llu\n", msg->mem_size); 485 fprintf(f, " next: %p\n", msg->next); 486 487 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) 488 { 489 fprintf(f, " slot[%d]: ", i); 490 _asl_msg_dump_kv(f, msg, msg->key[i]); 491 fprintf(f, " "); 492 _asl_msg_dump_kv(f, msg, msg->val[i]); 493 fprintf(f, " 0x%04x\n", msg->op[i]); 494 } 495 496 msg = msg->next; 497 } 498} 499 500#pragma mark - 501#pragma mark fetching contents 502 503/* 504 * Find the slot and page for an input key. 505 */ 506static uint32_t 507_asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage) 508{ 509 uint32_t i, len, slot; 510 uint16_t kx; 511 asl_msg_t *page; 512 const char *kp; 513 514 if (msg == NULL) return IndexNull; 515 if (key == NULL) return IndexNull; 516 517 i = 0; 518 slot = 0; 519 if (oslot != NULL) *oslot = slot; 520 521 page = msg; 522 if (opage != NULL) *opage = page; 523 524 len = strlen(key); 525 kx = _asl_msg_std_key(key, len); 526 527 forever 528 { 529 if (page->key[slot] != ASL_MSG_SLOT_FREE) 530 { 531 if (kx != 0) 532 { 533 if (page->key[slot] == kx) return i; 534 } 535 else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT) 536 { 537 /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */ 538 } 539 else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 540 { 541 memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 542 if (streq(key, kp)) return i; 543 } 544 else 545 { 546 kp = page->data + page->key[slot]; 547 if (streq(key, kp)) return i; 548 } 549 } 550 551 i++; 552 slot++; 553 if (oslot != NULL) *oslot = slot; 554 555 if (slot >= ASL_MSG_PAGE_SLOTS) 556 { 557 if (page->next == NULL) return IndexNull; 558 559 slot = 0; 560 if (oslot != NULL) *oslot = slot; 561 562 page = page->next; 563 if (opage != NULL) *opage = page; 564 } 565 } 566 567 return IndexNull; 568} 569 570/* 571 * Find page and slot for an "index". 572 */ 573static int 574_asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot) 575{ 576 uint32_t i, sx; 577 asl_msg_t *px; 578 579 if (msg == NULL) return -1; 580 581 *slot = IndexNull; 582 *page = NULL; 583 584 sx = 0; 585 586 /* find page */ 587 for (px = msg; px != NULL; px = px->next) 588 { 589 if (n > (sx + px->count)) 590 { 591 sx += px->count; 592 continue; 593 } 594 595 *page = px; 596 597 /* find slot */ 598 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) 599 { 600 if (px->key[i] != ASL_MSG_SLOT_FREE) 601 { 602 if (sx == n) 603 { 604 *slot = i; 605 return 0; 606 } 607 608 sx++; 609 } 610 } 611 } 612 613 return -1; 614} 615 616/* 617 * asl_msg_fetch: iterate over entries 618 * initial value of n should be 0. Subseqent calls should use the last 619 * returned value. Returns IndexNull when there are no more entries 620 * Sets the pointers for the next key, value, and op in the msg. 621 * The iterator encodes a page number and a slot number. 622 */ 623 624uint32_t 625asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout) 626{ 627 uint32_t p, xpn, xsn; 628 asl_msg_t *page = NULL; 629 630 if (msg == NULL) return IndexNull; 631 632 xsn = x >> 24; 633 xpn = x & 0x00ffffff; 634 635 /* slot number 0xff means we have run out entries */ 636 if (xsn == 0x000000ff) return IndexNull; 637 638 page = msg; 639 for (p = 0; p < xpn; p++) 640 { 641 page = page->next; 642 if (page == NULL) return IndexNull; 643 } 644 645 if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn); 646 if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn); 647 if (opout != NULL) *opout = (uint32_t)(page->op[xsn]); 648 649 /* advance to the next slot */ 650 forever 651 { 652 xsn++; 653 654 if (xsn >= ASL_MSG_PAGE_SLOTS) 655 { 656 if (page->next == NULL) return 0xff000000; 657 xsn = 0; 658 page = page->next; 659 xpn++; 660 } 661 662 if (page->key[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn); 663 } 664 665 return IndexNull; 666} 667 668int 669asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *opout) 670{ 671 uint32_t i, slot; 672 asl_msg_t *page; 673 674 if (msg == NULL) return -1; 675 if (valout != NULL) *valout = NULL; 676 if (opout != NULL) *opout = 0; 677 678 slot = IndexNull; 679 page = NULL; 680 681 i = _asl_msg_index(msg, key, &slot, &page); 682 if (i == IndexNull) return -1; 683 684 if (valout != NULL) *valout = _asl_msg_slot_val(page, slot); 685 if (opout != NULL) *opout = (uint32_t)(page->op[slot]); 686 687 return 0; 688} 689 690const char * 691asl_msg_get_val_for_key(asl_msg_t *msg, const char *key) 692{ 693 uint32_t slot; 694 asl_msg_t *page; 695 696 if (msg == NULL) return NULL; 697 698 slot = IndexNull; 699 page = NULL; 700 701 if (_asl_msg_index(msg, key, &slot, &page) == IndexNull) return NULL; 702 703 return _asl_msg_slot_val(page, slot); 704} 705 706const char * 707asl_msg_key(asl_msg_t *msg, uint32_t n) 708{ 709 uint32_t slot, i; 710 asl_msg_t *page; 711 712 if (msg == NULL) return NULL; 713 714 i = 0; 715 for (page = msg; page != NULL; page = page->next) 716 { 717 for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++) 718 { 719 if (page->key[slot] != ASL_MSG_SLOT_FREE) 720 { 721 if (i == n) return _asl_msg_slot_key(page, slot); 722 i++; 723 } 724 } 725 } 726 727 return NULL; 728} 729 730#pragma mark - 731#pragma mark adding and replacing contents 732 733static int 734_asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op) 735{ 736 uint32_t slot, keylen, vallen, total; 737 uint64_t klen, vlen; 738 uint16_t kx; 739 asl_msg_t *page, *last; 740 char *extkey, *extval; 741 742 if (msg == NULL) return -1; 743 if (key == NULL) return -1; 744 745 extkey = NULL; 746 extval = NULL; 747 748 keylen = strlen(key); 749 klen = keylen; 750 kx = _asl_msg_std_key(key, keylen); 751 752 if (kx == 0) keylen++; 753 else keylen = 0; 754 755 total = keylen; 756 757 vallen = 0; 758 if (val != NULL) 759 { 760 vallen = strlen(val) + 1; 761 vlen = vallen; 762 total += vallen; 763 } 764 765 /* check if one or both of key and value must be "external" (in its own malloced space) */ 766 if (keylen > ASL_MSG_PAGE_DATA_SIZE) 767 { 768 extkey = strdup(key); 769 keylen = sizeof(char *); 770 } 771 772 if (vallen > ASL_MSG_PAGE_DATA_SIZE) 773 { 774 extval = strdup(val); 775 vallen = sizeof(char *); 776 } 777 778 total = keylen + vallen; 779 if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extval == NULL) && (keylen > 0)) 780 { 781 extval = strdup(val); 782 vallen = sizeof(char *); 783 total = keylen + vallen; 784 } 785 786 if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extkey == NULL)) 787 { 788 extkey = strdup(key); 789 keylen = sizeof(char *); 790 total = keylen + vallen; 791 } 792 793 if (total > ASL_MSG_PAGE_DATA_SIZE) 794 { 795 /* can't happen, but... */ 796 if (extkey != NULL) free(extkey); 797 if (extval != NULL) free(extval); 798 return -1; 799 } 800 801 /* find a page with space for the key and value and a free slot*/ 802 slot = 0; 803 last = msg; 804 805 for (page = msg; page != NULL; page = page->next) 806 { 807 last = page; 808 809 if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size)) 810 { 811 /* check for a free slot */ 812 for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++); 813 if (slot < ASL_MSG_PAGE_SLOTS) break; 814 } 815 } 816 817 if (page == NULL) 818 { 819 /* allocate a new page and attach it */ 820 page = _asl_msg_make_page(); 821 if (page == NULL) 822 { 823 if (extkey != NULL) free(extkey); 824 if (extval != NULL) free(extval); 825 return -1; 826 } 827 828 last->next = page; 829 slot = 0; 830 } 831 832 /* copy key or external key pointer into page data */ 833 if (kx != 0) 834 { 835 page->key[slot] = kx; 836 } 837 else if (extkey == NULL) 838 { 839 page->key[slot] = page->data_size; 840 memcpy(page->data + page->data_size, key, keylen); 841 } 842 else 843 { 844 page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN; 845 memcpy(page->data + page->data_size, &extkey, keylen); 846 page->mem_size += klen; 847 } 848 849 page->data_size += keylen; 850 851 /* copy val or external val pointer into page data */ 852 page->val[slot] = ASL_MSG_SLOT_FREE; 853 854 if (val != NULL) 855 { 856 if (extval == NULL) 857 { 858 page->val[slot] = page->data_size; 859 memcpy(page->data + page->data_size, val, vallen); 860 } 861 else 862 { 863 page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN; 864 memcpy(page->data + page->data_size, &extval, vallen); 865 page->mem_size += vlen; 866 } 867 868 page->data_size += vallen; 869 } 870 871 /* set op */ 872 page->op[slot] = (uint16_t)op; 873 874 /* update page count */ 875 page->count++; 876 877 return 0; 878} 879 880/* 881 * Most of the code in asl_msg_set_key_val_op is concerned with trying to re-use 882 * space in an asl_msg_t page when given a new value for an existing key. 883 * If the key is new, we just call _asl_msg_new_key_val_op. 884 * 885 * Note that queries can have duplicate keys, so for ASL_TYPE_QUERY we just 886 * call through to _asl_msg_new_key_val_op. 887 */ 888static int 889_asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) 890{ 891 uint32_t i, slot, newexternal; 892 asl_msg_t *page; 893 uint32_t intvallen, extvallen, newvallen; 894 char *intval, *extval, *newval; 895 896 if (msg == NULL) return -1; 897 if (key == NULL) return -1; 898 899 slot = IndexNull; 900 page = NULL; 901 902 if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page))) 903 { 904 /* add key */ 905 return _asl_msg_new_key_val_op(msg, key, val, op); 906 } 907 908 intval = NULL; 909 intvallen = 0; 910 911 extval = NULL; 912 extvallen = 0; 913 914 if (page->val[slot] != ASL_MSG_SLOT_FREE) 915 { 916 if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 917 { 918 i = page->val[slot] & ASL_MSG_OFFSET_MASK; 919 memcpy(&extval, page->data + i, sizeof(char *)); 920 extvallen = sizeof(char *); 921 } 922 else 923 { 924 intval = page->data + page->val[slot]; 925 intvallen = strlen(intval) + 1; 926 } 927 } 928 929 /* replace val and op for existing entry */ 930 931 /* easy case - remove val */ 932 if (val == NULL) 933 { 934 if (extval != NULL) 935 { 936 page->mem_size -= (strlen(extval) + 1); 937 free(extval); 938 } 939 940 page->val[slot] = ASL_MSG_SLOT_FREE; 941 if (op != IndexNull) page->op[slot] = (uint16_t)op; 942 return 0; 943 } 944 945 /* trivial case - internal val doesn't change */ 946 if ((intval != NULL) && (streq(val, intval))) 947 { 948 if (op != IndexNull) page->op[slot] = (uint16_t)op; 949 return 0; 950 } 951 952 /* trivial case - external val doesn't change */ 953 if ((extval != NULL) && (streq(val, extval))) 954 { 955 if (op != IndexNull) page->op[slot] = (uint16_t)op; 956 return 0; 957 } 958 959 /* 960 * special case: we generally don't compress out holes in the data 961 * space, but if this is the last string in the currently used data space 962 * we can just back up the data_size and reset page->val[slot] 963 */ 964 i = page->val[slot] & ASL_MSG_OFFSET_MASK; 965 if ((intval != NULL) && ((i + intvallen) == page->data_size)) 966 { 967 page->val[slot] = ASL_MSG_SLOT_FREE; 968 page->data_size -= intvallen; 969 intval = NULL; 970 intvallen = 0; 971 } 972 else if ((extval != NULL) && ((i + extvallen) == page->data_size)) 973 { 974 page->val[slot] = ASL_MSG_SLOT_FREE; 975 page->data_size -= extvallen; 976 page->mem_size -= (strlen(extval) + 1); 977 free(extval); 978 extval = NULL; 979 extvallen = 0; 980 } 981 982 /* val changes - see if it needs to be external */ 983 newvallen = strlen(val) + 1; 984 newexternal = 0; 985 986 if (newvallen > ASL_MSG_PAGE_DATA_SIZE) 987 { 988 newexternal = 1; 989 newvallen = sizeof(char *); 990 } 991 992 /* check if there is room to change val in place */ 993 if (((extval != NULL) && (newvallen <= extvallen)) || ((extval == NULL) && (newvallen <= intvallen))) 994 { 995 if (extval != NULL) 996 { 997 page->mem_size -= (strlen(extval) + 1); 998 free(extval); 999 } 1000 1001 extval = NULL; 1002 1003 /* we can re-use the space of the old value */ 1004 i = page->val[slot] & ASL_MSG_OFFSET_MASK; 1005 1006 if (newexternal == 1) 1007 { 1008 /* create an external val and copy in the new pointer */ 1009 newval = strdup(val); 1010 if (newval == NULL) return -1; 1011 1012 page->mem_size += (strlen(newval) + 1); 1013 page->val[slot] = i | ASL_MSG_KV_EXTERN; 1014 memcpy(page->data + i, &newval, sizeof(char *)); 1015 } 1016 else 1017 { 1018 /* new internal value */ 1019 page->val[slot] = i; 1020 memcpy(page->data + i, val, newvallen); 1021 } 1022 1023 if (op != IndexNull) page->op[slot] = (uint16_t)op; 1024 return 0; 1025 } 1026 1027 /* we're done with the old value if it is external - free it now */ 1028 if (extval != NULL) 1029 { 1030 page->mem_size -= (strlen(extval) + 1); 1031 free(extval); 1032 } 1033 1034 extval = NULL; 1035 1036 if (newvallen <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size)) 1037 { 1038 /* can't re-use the old space, but there's room on the page */ 1039 i = page->data_size; 1040 page->data_size += newvallen; 1041 1042 if (newexternal == 1) 1043 { 1044 /* create an external val and copy in the new pointer */ 1045 newval = strdup(val); 1046 if (newval == NULL) return -1; 1047 1048 page->mem_size += (strlen(newval) + 1); 1049 page->val[slot] = i | ASL_MSG_KV_EXTERN; 1050 memcpy(page->data + i, &newval, sizeof(char *)); 1051 } 1052 else 1053 { 1054 /* new internal value */ 1055 page->val[slot] = i; 1056 memcpy(page->data + i, val, newvallen); 1057 } 1058 1059 if (op != IndexNull) page->op[slot] = (uint16_t)op; 1060 return 0; 1061 1062 } 1063 1064 /* no room on this page - free up existing entry and treat this as a new entry */ 1065 if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 1066 { 1067 memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 1068 page->mem_size -= (strlen(extval) + 1); 1069 free(extval); 1070 } 1071 1072 page->key[slot] = ASL_MSG_SLOT_FREE; 1073 page->val[slot] = ASL_MSG_SLOT_FREE; 1074 page->op[slot] = 0; 1075 1076 return _asl_msg_new_key_val_op(msg, key, val, op); 1077} 1078 1079int 1080asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op) 1081{ 1082 char *special, buf[512]; 1083 uint32_t i, len; 1084 int status; 1085 1086 /* Special case handling */ 1087 special = NULL; 1088 1089 /* if query modifier is set but op is zero, default to equality test */ 1090 if ((op != 0) && ((op & ASL_QUERY_OP_TRUE) == 0)) op |= ASL_QUERY_OP_EQUAL; 1091 1092 /* convert "Level" values to "0" through "7" */ 1093 if (streq(key, ASL_KEY_LEVEL)) 1094 { 1095 if (val == NULL) val = "7"; 1096 else if ((val[0] >= '0') && (val[0] <= '7') && (val[1] == '\0')) /* do nothing */; 1097 else if (strcaseeq(val, ASL_STRING_EMERG)) val = "0"; 1098 else if (strcaseeq(val, ASL_STRING_ALERT)) val = "1"; 1099 else if (strcaseeq(val, ASL_STRING_CRIT)) val = "2"; 1100 else if (strcaseeq(val, ASL_STRING_ERR)) val = "3"; 1101 else if (strcaseeq(val, ASL_STRING_WARNING)) val = "4"; 1102 else if (strcaseeq(val, ASL_STRING_NOTICE)) val = "5"; 1103 else if (strcaseeq(val, ASL_STRING_INFO)) val = "6"; 1104 else if (strcaseeq(val, ASL_STRING_DEBUG)) val = "7"; 1105 else val = "7"; 1106 } 1107 1108 /* strip trailing newlines from "Message" values */ 1109 if ((streq(key, ASL_KEY_MSG)) && (val != NULL)) 1110 { 1111 len = strlen(val); 1112 i = len; 1113 while ((i > 0) && (val[i - 1] == '\n')) i--; 1114 if (i == 0) val = NULL; 1115 else if (i < len) 1116 { 1117 /* use buf if it is big enough, else malloc a temporary buffer */ 1118 if (i < sizeof(buf)) 1119 { 1120 memcpy(buf, val, i); 1121 buf[i] = 0; 1122 val = (const char *)buf; 1123 } 1124 else 1125 { 1126 special = malloc(i + 1); 1127 if (special == NULL) return -1; 1128 memcpy(special, val, i); 1129 special[i] = 0; 1130 val = (const char *)special; 1131 } 1132 } 1133 } 1134 1135 status = _asl_msg_set_kvo(msg, key, val, op); 1136 1137 if (special != NULL) free(special); 1138 return status; 1139} 1140 1141int 1142asl_msg_set_key_val(asl_msg_t *msg, const char *key, const char *val) 1143{ 1144 return asl_msg_set_key_val_op(msg, key, val, 0); 1145} 1146 1147static void 1148_asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot) 1149{ 1150 char *ext; 1151 1152 if (page == NULL) return; 1153 if (slot >= ASL_MSG_PAGE_SLOTS) return; 1154 if (page->key[slot] == ASL_MSG_SLOT_FREE) return; 1155 1156 if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 1157 { 1158 memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 1159 page->mem_size -= (strlen(ext) + 1); 1160 free(ext); 1161 } 1162 1163 if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) 1164 { 1165 memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); 1166 page->mem_size -= (strlen(ext) + 1); 1167 free(ext); 1168 } 1169 1170 page->key[slot] = ASL_MSG_SLOT_FREE; 1171 page->val[slot] = ASL_MSG_SLOT_FREE; 1172 page->op[slot] = 0; 1173 1174 page->count--; 1175} 1176 1177/* 1178 * asl_msg_unset 1179 * Frees external key and val strings, but does not try to reclaim data space. 1180 */ 1181void 1182asl_msg_unset(asl_msg_t *msg, const char *key) 1183{ 1184 uint32_t i, slot; 1185 asl_msg_t *page; 1186 1187 if (msg == NULL) return; 1188 if (key == NULL) return; 1189 1190 slot = IndexNull; 1191 page = NULL; 1192 1193 i = _asl_msg_index(msg, key, &slot, &page); 1194 if (i == IndexNull) return; 1195 1196 _asl_msg_unset_page_slot(page, slot); 1197} 1198 1199void 1200asl_msg_unset_index(asl_msg_t *msg, uint32_t n) 1201{ 1202 uint32_t slot = IndexNull; 1203 asl_msg_t *page = NULL; 1204 1205 if (msg == NULL) return; 1206 1207 if (0 != _asl_msg_resolve_index(msg, n, &page, &slot)) return; 1208 _asl_msg_unset_page_slot(page, slot); 1209} 1210 1211#pragma mark - 1212#pragma mark copy and merge 1213 1214/* 1215 * Merge a key / val into a message (only ASL_TYPE_MSG). 1216 * Adds the key / val if the key is not found. 1217 * Does not replace the value if the key is found. 1218 */ 1219static void 1220_asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint16_t op) 1221{ 1222 uint32_t i, slot; 1223 asl_msg_t *page; 1224 1225 if (msg == NULL) return; 1226 if (key == NULL) return; 1227 1228 slot = IndexNull; 1229 page = NULL; 1230 1231 i = _asl_msg_index(msg, key, &slot, &page); 1232 if (i != IndexNull) return; 1233 1234 asl_msg_set_key_val_op(msg, key, val, op); 1235} 1236 1237/* 1238 * Merge msg into target (does not replace existing keys). 1239 * Creates a new asl_msg_t if target is NULL. 1240 * Returns target. 1241 */ 1242asl_msg_t * 1243asl_msg_merge(asl_msg_t *target, asl_msg_t *msg) 1244{ 1245 uint32_t x, type, isnew = 0; 1246 uint16_t op; 1247 const char *key, *val; 1248 1249 if (msg == NULL) return target; 1250 1251 type = asl_get_type((asl_object_t)msg); 1252 1253 if (target == NULL) 1254 { 1255 isnew = 1; 1256 target = asl_msg_new(type); 1257 } 1258 1259 for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op)) 1260 { 1261 if (type == ASL_TYPE_MSG) op = 0; 1262 if (isnew == 1) asl_msg_set_key_val_op(target, key, val, op); 1263 else _asl_msg_merge_key_val_op(target, key, val, op); 1264 } 1265 1266 return target; 1267} 1268 1269/* 1270 * replace key/value pairs from msg in target 1271 * Creates a new asl_msg_t if target is NULL. 1272 * Returns target. 1273 */ 1274static asl_msg_t * 1275asl_msg_replace(asl_msg_t *target, asl_msg_t *msg) 1276{ 1277 uint32_t x, type; 1278 uint16_t op; 1279 const char *key, *val; 1280 1281 if (msg == NULL) return target; 1282 1283 type = asl_get_type((asl_object_t)msg); 1284 1285 if (target == NULL) target = asl_msg_new(type); 1286 1287 for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op)) 1288 { 1289 if (type == ASL_TYPE_MSG) op = 0; 1290 asl_msg_set_key_val_op(target, key, val, op); 1291 } 1292 1293 return target; 1294} 1295 1296 1297/* 1298 * Copy msg. 1299 */ 1300asl_msg_t * 1301asl_msg_copy(asl_msg_t *msg) 1302{ 1303 return asl_msg_merge(NULL, msg); 1304} 1305 1306#pragma mark - 1307#pragma mark compare and test 1308 1309/* 1310 * Compare messages 1311 */ 1312static int 1313_asl_msg_equal(asl_msg_t *a, asl_msg_t *b) 1314{ 1315 uint32_t x; 1316 uint16_t oa, ob; 1317 const char *key, *va, *vb; 1318 1319 if (asl_msg_count(a) != asl_msg_count(b)) return 0; 1320 1321 key = NULL; 1322 va = NULL; 1323 oa = 0; 1324 1325 for (x = asl_msg_fetch(a, 0, &key, &va, &oa); x != IndexNull; x = asl_msg_fetch(a, x, &key, &va, &oa)) 1326 { 1327 if (asl_msg_lookup(b, key, &vb, &ob) != 0) return 0; 1328 if (strcmp(va, vb)) return 0; 1329 if ((a->asl_type == ASL_TYPE_QUERY) && (oa != ob)) return 0; 1330 } 1331 1332 return 1; 1333} 1334 1335static int 1336_asl_isanumber(const char *s) 1337{ 1338 int i; 1339 1340 if (s == NULL) return 0; 1341 1342 i = 0; 1343 if ((s[0] == '-') || (s[0] == '+')) i = 1; 1344 1345 if (s[i] == '\0') return 0; 1346 1347 for (; s[i] != '\0'; i++) 1348 { 1349 if (!isdigit(s[i])) return 0; 1350 } 1351 1352 return 1; 1353} 1354 1355static int 1356_asl_msg_basic_test(uint32_t op, const char *q, const char *m, uint32_t n) 1357{ 1358 int cmp; 1359 uint32_t t; 1360 int64_t nq, nm; 1361 int rflags; 1362 regex_t rex; 1363 1364 t = op & ASL_QUERY_OP_TRUE; 1365 1366 /* NULL value from query or message string fails */ 1367 if ((q == NULL) || (m == NULL)) return (t & ASL_QUERY_OP_NOT_EQUAL); 1368 1369 if (op & ASL_QUERY_OP_REGEX) 1370 { 1371 /* greater than or less than make no sense in substring search */ 1372 if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0; 1373 1374 memset(&rex, 0, sizeof(regex_t)); 1375 1376 rflags = REG_EXTENDED | REG_NOSUB; 1377 if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE; 1378 1379 /* A bad reqular expression matches nothing */ 1380 if (regcomp(&rex, q, rflags) != 0) return (t & ASL_QUERY_OP_NOT_EQUAL); 1381 1382 cmp = regexec(&rex, m, 0, NULL, 0); 1383 regfree(&rex); 1384 1385 if (t == ASL_QUERY_OP_NOT_EQUAL) return (cmp != 0); 1386 return (cmp == 0); 1387 } 1388 1389 if (op & ASL_QUERY_OP_NUMERIC) 1390 { 1391 if (_asl_isanumber(q) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL); 1392 if (_asl_isanumber(m) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL); 1393 1394 nq = atoll(q); 1395 nm = atoll(m); 1396 1397 switch (t) 1398 { 1399 case ASL_QUERY_OP_EQUAL: return (nm == nq); 1400 case ASL_QUERY_OP_GREATER: return (nm > nq); 1401 case ASL_QUERY_OP_GREATER_EQUAL: return (nm >= nq); 1402 case ASL_QUERY_OP_LESS: return (nm < nq); 1403 case ASL_QUERY_OP_LESS_EQUAL: return (nm <= nq); 1404 case ASL_QUERY_OP_NOT_EQUAL: return (nm != nq); 1405 default: return (t == ASL_QUERY_OP_NOT_EQUAL); 1406 } 1407 } 1408 1409 cmp = 0; 1410 if (op & ASL_QUERY_OP_CASEFOLD) 1411 { 1412 if (n == 0) cmp = strcasecmp(m, q); 1413 else cmp = strncasecmp(m, q, n); 1414 } 1415 else 1416 { 1417 if (n == 0) cmp = strcmp(m, q); 1418 else cmp = strncmp(m, q, n); 1419 } 1420 1421 switch (t) 1422 { 1423 case ASL_QUERY_OP_EQUAL: return (cmp == 0); 1424 case ASL_QUERY_OP_GREATER: return (cmp > 0); 1425 case ASL_QUERY_OP_GREATER_EQUAL: return (cmp >= 0); 1426 case ASL_QUERY_OP_LESS: return (cmp < 0); 1427 case ASL_QUERY_OP_LESS_EQUAL: return (cmp <= 0); 1428 case ASL_QUERY_OP_NOT_EQUAL: return (cmp != 0); 1429 } 1430 1431 return (t == ASL_QUERY_OP_NOT_EQUAL); 1432} 1433 1434static int 1435_asl_msg_test_substring(uint32_t op, const char *q, const char *m) 1436{ 1437 uint32_t t, i, d, lm, lq, match, newop; 1438 1439 t = op & ASL_QUERY_OP_TRUE; 1440 1441 lm = 0; 1442 if (m != NULL) lm = strlen(m); 1443 1444 lq = 0; 1445 if (q != NULL) lq = strlen(q); 1446 1447 /* NULL is a substring of any string */ 1448 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL); 1449 1450 /* A long string is defined to be not equal to a short string */ 1451 if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL); 1452 1453 /* greater than or less than make no sense in substring search */ 1454 if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0; 1455 1456 /* 1457 * We scan the string doing an equality test. 1458 * If the input test is equality, we stop as soon as we hit a match. 1459 * Otherwise we keep scanning the whole message string. 1460 */ 1461 newop = op & 0xff0; 1462 newop |= ASL_QUERY_OP_EQUAL; 1463 1464 match = 0; 1465 d = lm - lq; 1466 for (i = 0; i <= d; i++) 1467 { 1468 if (_asl_msg_basic_test(newop, q, m + i, lq) != 0) 1469 { 1470 if (t & ASL_QUERY_OP_EQUAL) return 1; 1471 match++; 1472 } 1473 } 1474 1475 /* If the input test was for equality, no matches were found */ 1476 if (t & ASL_QUERY_OP_EQUAL) return 0; 1477 1478 /* The input test was for not equal. Return true if no matches were found */ 1479 return (match == 0); 1480} 1481 1482static int 1483_asl_msg_test_prefix(uint32_t op, const char *q, const char *m) 1484{ 1485 uint32_t lm, lq, t; 1486 1487 t = op & ASL_QUERY_OP_TRUE; 1488 1489 lm = 0; 1490 if (m != NULL) lm = strlen(m); 1491 1492 lq = 0; 1493 if (q != NULL) lq = strlen(q); 1494 1495 /* NULL is a prefix of any string */ 1496 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL); 1497 1498 /* A long string is defined to be not equal to a short string */ 1499 if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL); 1500 1501 /* Compare two equal-length strings */ 1502 return _asl_msg_basic_test(op, q, m, lq); 1503} 1504 1505static int 1506_asl_msg_test_suffix(uint32_t op, const char *q, const char *m) 1507{ 1508 uint32_t lm, lq, d, t; 1509 1510 t = op & ASL_QUERY_OP_TRUE; 1511 1512 lm = 0; 1513 if (m != NULL) lm = strlen(m); 1514 1515 lq = 0; 1516 if (q != NULL) lq = strlen(q); 1517 1518 /* NULL is a suffix of any string */ 1519 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL); 1520 1521 /* A long string is defined to be not equal to a short string */ 1522 if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL); 1523 1524 /* Compare two equal-length strings */ 1525 d = lm - lq; 1526 return _asl_msg_basic_test(op, q, m + d, lq); 1527} 1528 1529/* 1530 * Splits out prefix, suffix, and substring tests. 1531 * Sends the rest to _asl_msg_basic_test(). 1532 */ 1533static int 1534_asl_msg_test_expression(uint32_t op, const char *q, const char *m) 1535{ 1536 uint32_t t; 1537 1538 t = op & ASL_QUERY_OP_TRUE; 1539 if (t == ASL_QUERY_OP_TRUE) return 1; 1540 1541 if (op & ASL_QUERY_OP_PREFIX) 1542 { 1543 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_substring(op, q, m); 1544 return _asl_msg_test_prefix(op, q, m); 1545 } 1546 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_suffix(op, q, m); 1547 1548 return _asl_msg_basic_test(op, q, m, 0); 1549} 1550 1551/* 1552 * Special case for comparing time values. 1553 * If both inputs are time strings, this compares the time 1554 * value in seconds. Otherwise it just does normal matching. 1555 */ 1556static int 1557_asl_msg_test_time_expression(uint32_t op, const char *q, const char *m) 1558{ 1559 time_t tq, tm; 1560 uint32_t t; 1561 1562 if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX)) return _asl_msg_test_expression(op, q, m); 1563 if ((q == NULL) || (m == NULL)) return _asl_msg_test_expression(op, q, m); 1564 1565 tq = asl_core_parse_time(q, NULL); 1566 if (tq < 0) return _asl_msg_test_expression(op, q, m); 1567 1568 tm = asl_core_parse_time(m, NULL); 1569 if (tm < 0) return _asl_msg_test_expression(op, q, m); 1570 1571 t = op & ASL_QUERY_OP_TRUE; 1572 1573 switch (t) 1574 { 1575 case ASL_QUERY_OP_FALSE: 1576 { 1577 return 0; 1578 } 1579 case ASL_QUERY_OP_EQUAL: 1580 { 1581 if (tm == tq) return 1; 1582 return 0; 1583 } 1584 case ASL_QUERY_OP_GREATER: 1585 { 1586 if (tm > tq) return 1; 1587 return 0; 1588 } 1589 case ASL_QUERY_OP_GREATER_EQUAL: 1590 { 1591 if (tm >= tq) return 1; 1592 return 0; 1593 } 1594 case ASL_QUERY_OP_LESS: 1595 { 1596 if (tm < tq) return 1; 1597 return 0; 1598 } 1599 case ASL_QUERY_OP_LESS_EQUAL: 1600 { 1601 if (tm <= tq) return 1; 1602 return 0; 1603 } 1604 case ASL_QUERY_OP_NOT_EQUAL: 1605 { 1606 if (tm != tq) return 1; 1607 return 0; 1608 } 1609 case ASL_QUERY_OP_TRUE: 1610 { 1611 return 1; 1612 } 1613 } 1614 1615 /* NOTREACHED */ 1616 return 0; 1617} 1618 1619/* test a query against a message */ 1620__private_extern__ int 1621_asl_msg_test(asl_msg_t *q, asl_msg_t *m) 1622{ 1623 uint32_t i, t, x; 1624 uint16_t op; 1625 int cmp; 1626 const char *kq, *vq, *vm; 1627 1628 /* 1629 * Check each simple expression (key op val) separately. 1630 * The query suceeds (returns 1) if all simple expressions 1631 * succeed (i.e. AND the simple expressions). 1632 */ 1633 1634 kq = NULL; 1635 vq = NULL; 1636 op = 0; 1637 1638 for (x = asl_msg_fetch(q, 0, &kq, &vq, &op); x != IndexNull; x = asl_msg_fetch(q, x, &kq, &vq, &op)) 1639 { 1640 /* Find query key in the message */ 1641 vm = NULL; 1642 i = asl_msg_lookup(m, kq, &vm, NULL); 1643 1644 /* ASL_QUERY_OP_TRUE tests if key is present in the message */ 1645 t = op & ASL_QUERY_OP_TRUE; 1646 if (t == ASL_QUERY_OP_TRUE) 1647 { 1648 if (i != 0) return 0; 1649 continue; 1650 } 1651 1652 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */ 1653 if (t == ASL_QUERY_OP_FALSE) 1654 { 1655 if (i == 0) return 0; 1656 continue; 1657 } 1658 1659 if (i != 0) 1660 { 1661 /* the message does NOT have query key - fail unless we are testing not equal */ 1662 if (t == ASL_QUERY_OP_NOT_EQUAL) continue; 1663 return 0; 1664 } 1665 1666 cmp = 1; 1667 if (streq(kq, ASL_KEY_TIME)) 1668 { 1669 cmp = _asl_msg_test_time_expression(op, vq, vm); 1670 } 1671 else 1672 { 1673 cmp = _asl_msg_test_expression(op, vq, vm); 1674 } 1675 1676 if (cmp == 0) return 0; 1677 } 1678 1679 return 1; 1680} 1681 1682/* returns 1 if a and b match, 0 otherwise */ 1683int 1684asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) 1685{ 1686 1687 if (a == NULL) return 0; 1688 if (b == NULL) return 0; 1689 1690 if (a->asl_type == b->asl_type) return _asl_msg_equal(a, b); 1691 if (a->asl_type == ASL_TYPE_QUERY) return _asl_msg_test(a, b); 1692 return _asl_msg_test(b, a); 1693} 1694 1695/* 1696 * Test a message against a query list. 1697 * Returns 1 if msg matches any query in the list, 0 otherwise. 1698 * Returns 1 if the query list is NULL or empty. 1699 */ 1700int 1701asl_msg_cmp_list(asl_msg_t *msg, asl_msg_list_t *list) 1702{ 1703 uint32_t i; 1704 1705 if (msg == NULL) return 0; 1706 if (list == NULL) return 1; 1707 if (list->count == 0) return 1; 1708 1709 for (i = 0; i < list->count; i++) 1710 { 1711 if (_asl_msg_test(list->msg[i], msg)) return 1; 1712 } 1713 1714 return 0; 1715} 1716 1717#pragma mark - 1718#pragma mark string representation 1719 1720static char * 1721_asl_time_string(const char *infmt, const char *str, const char *nano) 1722{ 1723 time_t tick, off; 1724 struct tm stm; 1725 char *ltime, *out, *p, *q; 1726 char ltbuf[32], nanobuf[16], fmt[32], zstr[8]; 1727 time_t zh, zm; 1728 uint32_t subsec = 0; 1729 bool neg; 1730 1731 out = NULL; 1732 memset(zstr, 0, sizeof(zstr)); 1733 zh = 0; 1734 zm = 0; 1735 off = 0; 1736 neg = false; 1737 1738 /* 1739 * The longest infmt string we understand is "-hh:mm.N" (8 chars), so 1740 * it is safe to ignore the input if it doesn't fit in the temp buffer. 1741 * The default is local time zone format. 1742 */ 1743 if (infmt == NULL) 1744 { 1745 snprintf(fmt, sizeof(fmt), "local"); 1746 } 1747 else if (strlen(infmt) >= sizeof (fmt)) 1748 { 1749 snprintf(fmt, sizeof(fmt), "local"); 1750 } 1751 else 1752 { 1753 snprintf(fmt, sizeof(fmt), "%s", infmt); 1754 1755 p = fmt; 1756 q = strchr(fmt, '.'); 1757 if (q != NULL) 1758 { 1759 *q = '\0'; 1760 q++; 1761 if (q != '\0') subsec = atoi(q); 1762 } 1763 } 1764 1765 nanobuf[0] = '\0'; 1766 1767 if (subsec > 0) 1768 { 1769 uint32_t nsec = 0; 1770 if (nano != NULL) nsec = atoi(nano); 1771 snprintf(nanobuf, sizeof(nanobuf), ".%09u", nsec); 1772 if (subsec > 9) subsec = 9; 1773 nanobuf[subsec + 1] = '\0'; 1774 } 1775 1776 tick = 0; 1777 if (str != NULL) tick = asl_core_parse_time(str, NULL); 1778 1779 if ((!strcasecmp(fmt, "lcl")) || (!strcasecmp(fmt, "local"))) 1780 { 1781 ltime = ctime_r(&tick, ltbuf); 1782 if (ltime == NULL) return NULL; 1783 ltime[19] = '\0'; 1784 asprintf(&out, "%s%s", ltime + 4, nanobuf); 1785 return out; 1786 } 1787 1788 if ((!strcasecmp(fmt, "jz")) || (!strcasecmp(fmt, "iso8601")) || (!strcasecmp(fmt, "iso8601e"))) 1789 { 1790 char sep = ' '; 1791 if (!strncasecmp(fmt, "iso8601", 7)) sep = 'T'; 1792 1793 if (NULL == localtime_r(&tick, &stm)) return NULL; 1794 1795 off = stm.tm_gmtoff; 1796 if ((neg = (off < 0))) off *= -1; 1797 zh = off / 3600; 1798 off %= 3600; 1799 zm = off / 60; 1800 1801 if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); 1802 else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); 1803 1804 asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr); 1805 return out; 1806 } 1807 1808 if (!strcasecmp(fmt, "iso8601b")) 1809 { 1810 if (NULL == localtime_r(&tick, &stm)) return NULL; 1811 1812 off = stm.tm_gmtoff; 1813 if ((neg = (off < 0))) off *= -1; 1814 zh = off / 3600; 1815 off %= 3600; 1816 zm = off / 60; 1817 1818 if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); 1819 else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); 1820 1821 asprintf(&out, "%d%02d%02dT%02d%02d%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr); 1822 return out; 1823 } 1824 1825 if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw"))) 1826 { 1827 asprintf(&out, "%lu%s", tick, nanobuf); 1828 return out; 1829 } 1830 1831 if (!strcasecmp(fmt, "j")) 1832 { 1833 if (NULL == localtime_r(&tick, &stm)) return NULL; 1834 asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf); 1835 return out; 1836 } 1837 1838 if ((!strcasecmp(fmt, "utc")) || (!strcasecmp(fmt, "zulu")) || (!strcasecmp(fmt, "iso8601z")) || (!strcasecmp(fmt, "iso8601ez"))) 1839 { 1840 char sep = ' '; 1841 if (!strncasecmp(fmt, "iso8601", 7)) sep = 'T'; 1842 1843 if (NULL == gmtime_r(&tick, &stm)) return NULL; 1844 asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%sZ", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf); 1845 return out; 1846 } 1847 1848 if (!strcasecmp(fmt, "iso8601bz")) 1849 { 1850 if (NULL == gmtime_r(&tick, &stm)) return NULL; 1851 asprintf(&out, "%d%02d%02dT%02d%02d%02d%sZ", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf); 1852 return out; 1853 } 1854 1855 if ((fmt[1] == '\0') && (((fmt[0] >= 'a') && (fmt[0] <= 'z')) || ((fmt[0] >= 'A') && (fmt[0] <= 'Z')))) 1856 { 1857 char z = fmt[0]; 1858 if (z >= 'a') z -= 32; 1859 1860 if (z == 'Z') off = 0; 1861 else if ((z >= 'A') && (z <= 'I')) off = ((z - 'A') + 1) * SEC_PER_HOUR; 1862 else if ((z >= 'K') && (z <= 'M')) off = (z - 'A') * SEC_PER_HOUR; 1863 else if ((z >= 'N') && (z <= 'Y')) off = ('M' - z) * SEC_PER_HOUR; 1864 else return NULL; 1865 } 1866 else 1867 { 1868 if (fmt[0] == '-') neg = true; 1869 if ((*p == '-') || (*p == '+')) p++; 1870 if ((*p) >= '0' && (*p <= '9')) 1871 { 1872 zh = atoi(p); 1873 1874 p = strchr(p, ':'); 1875 if (p != NULL) zm = atoi(p + 1); 1876 } 1877 else 1878 { 1879 return NULL; 1880 } 1881 1882 off = (zh * 3600) + (zm * 60); 1883 if (neg) off *= -1; 1884 1885 if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); 1886 else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); 1887 } 1888 1889 1890 tick += off; 1891 1892 memset(&stm, 0, sizeof (struct tm)); 1893 if (NULL == gmtime_r(&tick, &stm)) return NULL; 1894 1895 if ((fmt[0] >= 'A') && (fmt[0] <= 'Z')) 1896 { 1897 asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%s%c", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, fmt[0]); 1898 } 1899 else if ((fmt[0] >= 'a') && (fmt[0] <= 'z')) 1900 { 1901 asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%s%c", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, fmt[0] - 32); 1902 } 1903 else 1904 { 1905 asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr); 1906 } 1907 1908 return out; 1909} 1910 1911 1912/* called from asl_format_message and _asl_send_message */ 1913__private_extern__ asl_string_t * 1914asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt) 1915{ 1916 uint32_t i, x, count; 1917 const char *key, *val, *nano; 1918 asl_string_t *str; 1919 1920 if (msg == NULL) return NULL; 1921 1922 count = asl_msg_count(msg); 1923 if (count == 0) return NULL; 1924 1925 str = asl_string_new(encoding); 1926 if (str == NULL) return NULL; 1927 1928 key = NULL; 1929 val = NULL; 1930 i = 0; 1931 1932 nano = NULL; 1933 asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL); 1934 1935 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL)) 1936 { 1937 if (key == NULL) continue; 1938 1939 if (i > 0) asl_string_append_char_no_encoding(str, ' '); 1940 1941 asl_string_append_char_no_encoding(str, '['); 1942 asl_string_append_asl_key(str, key); 1943 1944 if (!strcmp(key, ASL_KEY_TIME)) 1945 { 1946 char *vtime = NULL; 1947 asl_string_append_char_no_encoding(str, ' '); 1948 1949 if (val != NULL) vtime = _asl_time_string(tfmt, val, nano); 1950 1951 if (vtime != NULL) 1952 { 1953 asl_string_append_no_encoding(str, vtime); 1954 free(vtime); 1955 } 1956 else 1957 { 1958 asl_string_append_char_no_encoding(str, '0'); 1959 } 1960 } 1961 else if (val != NULL) 1962 { 1963 asl_string_append_char_no_encoding(str, ' '); 1964 asl_string_append(str, val); 1965 } 1966 1967 asl_string_append_char_no_encoding(str, ']'); 1968 1969 i++; 1970 } 1971 1972 return str; 1973} 1974 1975asl_string_t * 1976asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) 1977{ 1978 const char *key, *val; 1979 uint32_t i, x; 1980 uint16_t op; 1981 1982 if (msg == NULL) return str; 1983 1984 if (msg->asl_type == ASL_TYPE_QUERY) asl_string_append(str, "Q "); 1985 1986 i = 0; 1987 for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, &op)) 1988 { 1989 if (i != 0) asl_string_append_char_no_encoding(str, ' '); 1990 i++; 1991 1992 asl_string_append_char_no_encoding(str, '['); 1993 1994 if (msg->asl_type == ASL_TYPE_QUERY) 1995 { 1996 asl_string_append_op(str, op); 1997 asl_string_append_char_no_encoding(str, ' '); 1998 } 1999 2000 asl_string_append_asl_key(str, key); 2001 2002 if (val != NULL) 2003 { 2004 asl_string_append_char_no_encoding(str, ' '); 2005 asl_string_append(str, val); 2006 } 2007 2008 asl_string_append_char_no_encoding(str, ']'); 2009 } 2010 2011 return str; 2012} 2013 2014char * 2015asl_msg_to_string(asl_msg_t *msg, uint32_t *len) 2016{ 2017 char *out; 2018 asl_string_t *str = asl_string_new(ASL_ENCODE_ASL); 2019 if (str == NULL) return NULL; 2020 2021 str = asl_string_append_asl_msg(str, msg); 2022 *len = asl_string_length(str); 2023 out = asl_string_release_return_bytes(str); 2024 return out; 2025} 2026 2027static uint32_t 2028_asl_msg_op_from_string(char *o) 2029{ 2030 uint32_t op, i; 2031 2032 op = ASL_QUERY_OP_NULL; 2033 2034 if (o == NULL) return op; 2035 2036 for (i = 0; o[i] != '\0'; i++) 2037 { 2038 if (o[i] == '.') return ASL_QUERY_OP_NULL; 2039 if (o[i] == 'C') op |= ASL_QUERY_OP_CASEFOLD; 2040 if (o[i] == 'R') op |= ASL_QUERY_OP_REGEX; 2041 if (o[i] == 'N') op |= ASL_QUERY_OP_NUMERIC; 2042 if (o[i] == 'S') op |= ASL_QUERY_OP_SUBSTRING; 2043 if (o[i] == 'A') op |= ASL_QUERY_OP_PREFIX; 2044 if (o[i] == 'Z') op |= ASL_QUERY_OP_SUFFIX; 2045 if (o[i] == '<') op |= ASL_QUERY_OP_LESS; 2046 if (o[i] == '>') op |= ASL_QUERY_OP_GREATER; 2047 if (o[i] == '=') op |= ASL_QUERY_OP_EQUAL; 2048 if (o[i] == '!') op |= ASL_QUERY_OP_NOT_EQUAL; 2049 if (o[i] == 'T') op |= ASL_QUERY_OP_TRUE; 2050 } 2051 2052 return op; 2053} 2054 2055static char * 2056_asl_msg_get_next_word(char **p, uint32_t *tt, uint32_t spacedel) 2057{ 2058 char *str, *out, c, oval; 2059 uint32_t i, len, n, outlen; 2060 2061 *tt = TOKEN_NULL; 2062 2063 if (p == NULL) return NULL; 2064 if (*p == NULL) return NULL; 2065 if (**p == '\0') return NULL; 2066 2067 /* skip one space if it's there (word separator) */ 2068 if (**p == ' ') (*p)++; 2069 2070 /* skip leading white space */ 2071 if (spacedel != 0) 2072 { 2073 while ((**p == ' ') || (**p == '\t')) (*p)++; 2074 } 2075 2076 if (**p == '\0') return NULL; 2077 if (**p == '\n') return NULL; 2078 2079 str = *p; 2080 2081 /* opening [ */ 2082 if (**p == '[') 2083 { 2084 *tt = TOKEN_OPEN; 2085 2086 (*p)++; 2087 out = malloc(2); 2088 if (out == NULL) return NULL; 2089 2090 out[0] = '['; 2091 out[1] = '\0'; 2092 return out; 2093 } 2094 2095 /* scan for token and calulate it's length (input and decoded output len) */ 2096 len = 0; 2097 outlen = 0; 2098 2099 forever 2100 { 2101 c = str[len]; 2102 2103 /* stop scanning when we hit a delimiter */ 2104 if (((spacedel != 0) && (c == ' ')) || (c == ']') || (c == '\0')) break; 2105 2106 if (c == '\\') 2107 { 2108 len++; 2109 c = str[len]; 2110 if ((c == 'a') || (c == 'b') || (c == 't') || (c == 'n') || (c == 'v') || (c == 'f') || (c == 'r') || (c == 's') || (c == '[') || (c == '\\') || (c == ']')) 2111 { 2112 } 2113 else if (c == '^') 2114 { 2115 if (str[++len] == '\0') return NULL; 2116 } 2117 else if (c == 'M') 2118 { 2119 if (str[++len] == '\0') return NULL; 2120 if (str[++len] == '\0') return NULL; 2121 } 2122 else if ((c >= '0') && (c <= '3')) 2123 { 2124 if (str[++len] == '\0') return NULL; 2125 if (str[++len] == '\0') return NULL; 2126 } 2127 else 2128 { 2129 return NULL; 2130 } 2131 } 2132 2133 len++; 2134 outlen++; 2135 } 2136 2137 (*p) += len; 2138 2139 if ((len == 0) && (**p == ']')) 2140 { 2141 *tt = TOKEN_CLOSE; 2142 (*p)++; 2143 out = malloc(2); 2144 if (out == NULL) return NULL; 2145 2146 out[0] = ']'; 2147 out[1] = '\0'; 2148 return out; 2149 } 2150 2151 *tt = TOKEN_INT; 2152 2153 out = malloc(outlen + 1); 2154 if (out == NULL) return NULL; 2155 2156 n = 0; 2157 for (i = 0; i < len; i++) 2158 { 2159 c = str[i]; 2160 2161 if (c == '\\') 2162 { 2163 *tt = TOKEN_WORD; 2164 2165 i++; 2166 c = str[i]; 2167 if (c == 'a') 2168 { 2169 out[n++] = '\a'; 2170 } 2171 else if (c == 'b') 2172 { 2173 out[n++] = '\b'; 2174 } 2175 else if (c == 't') 2176 { 2177 out[n++] = '\t'; 2178 } 2179 else if (c == 'n') 2180 { 2181 out[n++] = '\n'; 2182 } 2183 else if (c == 'v') 2184 { 2185 out[n++] = '\v'; 2186 } 2187 else if (c == 'f') 2188 { 2189 out[n++] = '\f'; 2190 } 2191 else if (c == 'r') 2192 { 2193 out[n++] = '\r'; 2194 } 2195 else if (c == 's') 2196 { 2197 out[n++] = ' '; 2198 } 2199 else if (c == '[') 2200 { 2201 out[n++] = '['; 2202 } 2203 else if (c == '\\') 2204 { 2205 out[n++] = '\\'; 2206 } 2207 else if (c == ']') 2208 { 2209 out[n++] = ']'; 2210 } 2211 else if (c == '^') 2212 { 2213 i++; 2214 if (str[i] == '?') out[n++] = 127; 2215 else out[n++] = str[i] - 64; 2216 } 2217 else if (c == 'M') 2218 { 2219 i++; 2220 c = str[i]; 2221 if (c == '^') 2222 { 2223 i++; 2224 if (str[i] == '?') out[n++] = 255; 2225 else out[n++] = str[i] + 64; 2226 } 2227 else if (c == '-') 2228 { 2229 i++; 2230 out[n++] = str[i] + 128; 2231 } 2232 else 2233 { 2234 *tt = TOKEN_NULL; 2235 free(out); 2236 return NULL; 2237 } 2238 2239 } 2240 else if ((c >= '0') && (c <= '3')) 2241 { 2242 oval = (c - '0') * 64; 2243 2244 i++; 2245 c = str[i]; 2246 if ((c < '0') || (c > '7')) 2247 { 2248 *tt = TOKEN_NULL; 2249 free(out); 2250 return NULL; 2251 } 2252 2253 oval += ((c - '0') * 8); 2254 2255 i++; 2256 c = str[i]; 2257 if ((c < '0') || (c > '7')) 2258 { 2259 *tt = TOKEN_NULL; 2260 free(out); 2261 return NULL; 2262 } 2263 2264 oval += (c - '0'); 2265 2266 out[n++] = oval; 2267 } 2268 else 2269 { 2270 *tt = TOKEN_NULL; 2271 free(out); 2272 return NULL; 2273 } 2274 } 2275 else 2276 { 2277 2278 if ((c < '0') || (c > '9')) *tt = TOKEN_WORD; 2279 out[n++] = c; 2280 } 2281 } 2282 2283 out[n] = '\0'; 2284 2285 return out; 2286} 2287 2288asl_msg_t * 2289asl_msg_from_string(const char *buf) 2290{ 2291 uint32_t tt, type, op; 2292 char *k, *v, *o, *p; 2293 asl_msg_t *out; 2294 2295 if (buf == NULL) return NULL; 2296 2297 type = ASL_TYPE_MSG; 2298 p = (char *)buf; 2299 2300 k = _asl_msg_get_next_word(&p, &tt, 1); 2301 if (k == NULL) return NULL; 2302 2303 if (streq(k, "Q")) 2304 { 2305 type = ASL_TYPE_QUERY; 2306 free(k); 2307 2308 k = _asl_msg_get_next_word(&p, &tt, 1); 2309 } 2310 else if (tt == TOKEN_INT) 2311 { 2312 /* Leading integer is a string length - skip it */ 2313 free(k); 2314 k = _asl_msg_get_next_word(&p, &tt, 1); 2315 if (k == NULL) return NULL; 2316 } 2317 2318 out = asl_msg_new(ASL_TYPE_MSG); 2319 if (out == NULL) return NULL; 2320 2321 out->asl_type = type; 2322 2323 /* OPEN WORD [WORD [WORD]] CLOSE */ 2324 while (k != NULL) 2325 { 2326 op = ASL_QUERY_OP_NULL; 2327 2328 if (tt != TOKEN_OPEN) 2329 { 2330 asl_msg_release(out); 2331 return NULL; 2332 } 2333 2334 free(k); 2335 2336 /* get op for query type */ 2337 if (type == ASL_TYPE_QUERY) 2338 { 2339 o = _asl_msg_get_next_word(&p, &tt, 1); 2340 if ((o == NULL) || (tt != TOKEN_WORD)) 2341 { 2342 if (o != NULL) free(o); 2343 asl_msg_release(out); 2344 return NULL; 2345 } 2346 2347 op = _asl_msg_op_from_string(o); 2348 free(o); 2349 } 2350 2351 k = _asl_msg_get_next_word(&p, &tt, 1); 2352 if (tt == TOKEN_INT) tt = TOKEN_WORD; 2353 if ((k == NULL) || (tt != TOKEN_WORD)) 2354 { 2355 if (k != NULL) free(k); 2356 asl_msg_release(out); 2357 return NULL; 2358 } 2359 2360 v = _asl_msg_get_next_word(&p, &tt, 0); 2361 if (tt == TOKEN_INT) tt = TOKEN_WORD; 2362 if (v == NULL) 2363 { 2364 asl_msg_set_key_val_op(out, k, NULL, op); 2365 free(k); 2366 break; 2367 } 2368 2369 if (tt == TOKEN_CLOSE) 2370 { 2371 asl_msg_set_key_val_op(out, k, NULL, op); 2372 } 2373 else if (tt == TOKEN_WORD) 2374 { 2375 asl_msg_set_key_val_op(out, k, v, op); 2376 } 2377 else 2378 { 2379 if (k != NULL) free(k); 2380 if (v != NULL) free(v); 2381 asl_msg_release(out); 2382 return NULL; 2383 } 2384 2385 if (k != NULL) free(k); 2386 if (v != NULL) free(v); 2387 2388 if (tt != TOKEN_CLOSE) 2389 { 2390 k = _asl_msg_get_next_word(&p, &tt, 1); 2391 if (k == NULL) break; 2392 2393 if (tt != TOKEN_CLOSE) 2394 { 2395 asl_msg_release(out); 2396 return NULL; 2397 } 2398 2399 free(k); 2400 } 2401 2402 k = _asl_msg_get_next_word(&p, &tt, 1); 2403 if (k == NULL) break; 2404 } 2405 2406 return out; 2407} 2408 2409static const char * 2410_asl_level_string(int level) 2411{ 2412 if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG; 2413 if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT; 2414 if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT; 2415 if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR; 2416 if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING; 2417 if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE; 2418 if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO; 2419 if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG; 2420 return "unknown"; 2421} 2422 2423static const char * 2424_asl_level_char(int level) 2425{ 2426 if (level == ASL_LEVEL_EMERG) return "P"; 2427 if (level == ASL_LEVEL_ALERT) return "A"; 2428 if (level == ASL_LEVEL_CRIT) return "C"; 2429 if (level == ASL_LEVEL_ERR) return "E"; 2430 if (level == ASL_LEVEL_WARNING) return "W"; 2431 if (level == ASL_LEVEL_NOTICE) return "N"; 2432 if (level == ASL_LEVEL_INFO) return "I"; 2433 if (level == ASL_LEVEL_DEBUG) return "D"; 2434 return "?"; 2435} 2436 2437/* 2438 * Find the value for a key in a message and append a formatted value to str. 2439 * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)). 2440 * WARNING: modifies kf! 2441 */ 2442static asl_string_t * 2443_asl_string_append_value_for_key_format(asl_string_t *str, asl_msg_t *msg, char *kf, const char *tfmt) 2444{ 2445 uint32_t i, get_fmt; 2446 int status; 2447 char *key, *fmt; 2448 const char *mval, *nano; 2449 2450 if (str == NULL) return NULL; 2451 if (msg == NULL) return str; 2452 if (kf == NULL) return str; 2453 2454 key = NULL; 2455 fmt = NULL; 2456 get_fmt = 0; 2457 2458 for (i = 0; kf[i] != '\0'; i++) 2459 { 2460 if (kf[i] == ')') 2461 { 2462 kf[i] = '\0'; 2463 get_fmt = 1; 2464 } 2465 else if (kf[i] != '(') 2466 { 2467 if (key == NULL) key = kf + i; 2468 else if ((get_fmt == 1) && (fmt == NULL)) fmt = kf + i; 2469 } 2470 } 2471 2472 if (key == NULL) return str; 2473 2474 nano = NULL; 2475 asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL); 2476 2477 status = asl_msg_lookup(msg, key, &mval, NULL); 2478 if ((status != 0) || (mval == NULL)) return str; 2479 2480 if (!strcmp(key, ASL_KEY_TIME)) 2481 { 2482 char *fval = NULL; 2483 2484 /* format in $((Time)(fmt)) overrides tfmt */ 2485 if (fmt == NULL) 2486 { 2487 fval = _asl_time_string(tfmt, mval, nano); 2488 } 2489 else 2490 { 2491 fval = _asl_time_string(fmt, mval, nano); 2492 } 2493 2494 if (fval != NULL) 2495 { 2496 asl_string_append_no_encoding(str, fval); 2497 free(fval); 2498 } 2499 else 2500 { 2501 asl_string_append_char_no_encoding(str, '0'); 2502 } 2503 2504 return str; 2505 } 2506 2507 /* Level: num str */ 2508 if (!strcmp(key, ASL_KEY_LEVEL)) 2509 { 2510 if (fmt == NULL) 2511 { 2512 asl_string_append_no_encoding(str, mval); 2513 } 2514 else if (!strcmp(fmt, "str")) 2515 { 2516 mval = _asl_level_string(atoi(mval)); 2517 asl_string_append_no_encoding(str, mval); 2518 } 2519 else if (!strcmp(fmt, "char")) 2520 { 2521 mval = _asl_level_char(atoi(mval)); 2522 asl_string_append_no_encoding(str, mval); 2523 } 2524 else 2525 { 2526 asl_string_append_no_encoding(str, mval); 2527 } 2528 2529 return str; 2530 } 2531 2532 return asl_string_append(str, mval); 2533} 2534 2535/* 2536 * format a message for printing 2537 * out parameter len returns string length including trailing NUL 2538 */ 2539char * 2540asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t text_encoding, uint32_t *len) 2541{ 2542 char *out, *vtime, *k, c, skey[512], tfmt_ext[16]; 2543 const char *vhost, *vpid, *vsender, *vmessage, *vlevel, *vrefproc, *vrefpid, *v, *key, *val, *nano; 2544 int i, j, l, mf, paren, oval, level; 2545 uint32_t x, cursor; 2546 asl_string_t *str; 2547 uint8_t *b64; 2548 2549 out = NULL; 2550 *len = 0; 2551 2552 if (msg == NULL) return NULL; 2553 2554 mf = MFMT_RAW; 2555 2556 if (mfmt == NULL) mf = MFMT_RAW; 2557 else if (!strcmp(mfmt, ASL_MSG_FMT_RAW)) mf = MFMT_RAW; 2558 else if (!strcmp(mfmt, ASL_MSG_FMT_STD)) mf = MFMT_STD; 2559 else if (!strcmp(mfmt, ASL_MSG_FMT_BSD)) mf = MFMT_BSD; 2560 else if (!strcmp(mfmt, ASL_MSG_FMT_XML)) mf = MFMT_XML; 2561 else if (!strcmp(mfmt, ASL_MSG_FMT_MSG)) mf = MFMT_MSG; 2562 else if ((!strncmp(mfmt, ASL_MSG_FMT_RAW, 3)) && (mfmt[3] == '.')) 2563 { 2564 mf = MFMT_RAW; 2565 if ((tfmt == NULL) && (mfmt[4] != '\0')) 2566 { 2567 snprintf(tfmt_ext, sizeof(tfmt_ext), "sec.%s", mfmt + 4); 2568 tfmt = (const char *)tfmt_ext; 2569 } 2570 } 2571 else if ((!strncmp(mfmt, ASL_MSG_FMT_STD, 3)) && (mfmt[3] == '.')) 2572 { 2573 mf = MFMT_STD; 2574 if ((tfmt == NULL) && (mfmt[4] != '\0')) 2575 { 2576 snprintf(tfmt_ext, sizeof(tfmt_ext), "lcl.%s", mfmt + 4); 2577 tfmt = (const char *)tfmt_ext; 2578 } 2579 } 2580 else if ((!strncmp(mfmt, ASL_MSG_FMT_BSD, 3)) && (mfmt[3] == '.')) 2581 { 2582 mf = MFMT_BSD; 2583 if ((tfmt == NULL) && (mfmt[4] != '\0')) 2584 { 2585 snprintf(tfmt_ext, sizeof(tfmt_ext), "lcl.%s", mfmt + 4); 2586 tfmt = (const char *)tfmt_ext; 2587 } 2588 } 2589 else mf = MFMT_STR; 2590 2591 nano = NULL; 2592 asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL); 2593 2594 if (mf == MFMT_RAW) 2595 { 2596 str = asl_msg_to_string_raw(text_encoding, msg, tfmt); 2597 asl_string_append_char_no_encoding(str, '\n'); 2598 2599 *len = asl_string_length(str); 2600 out = asl_string_release_return_bytes(str); 2601 return out; 2602 } 2603 2604 if (mf == MFMT_MSG) 2605 { 2606 vmessage = NULL; 2607 2608 if (asl_msg_lookup(msg, ASL_KEY_MSG, &vmessage, NULL) != 0) return NULL; 2609 2610 str = asl_string_new(text_encoding); 2611 if (str == NULL) return NULL; 2612 2613 asl_string_append(str, vmessage); 2614 asl_string_append_char_no_encoding(str, '\n'); 2615 2616 *len = asl_string_length(str); 2617 out = asl_string_release_return_bytes(str); 2618 return out; 2619 } 2620 2621 if ((mf == MFMT_STD) || (mf == MFMT_BSD)) 2622 { 2623 /* COMMON: Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/ 2624 /* BSD: <COMMON>: message */ 2625 /* STD: <COMMON> <Level>: message */ 2626 2627 v = NULL; 2628 vtime = NULL; 2629 vhost = NULL; 2630 vsender = NULL; 2631 vpid = NULL; 2632 vmessage = NULL; 2633 vlevel = NULL; 2634 vrefproc = NULL; 2635 vrefpid = NULL; 2636 2637 if (asl_msg_lookup(msg, ASL_KEY_TIME, &v, NULL) == 0) 2638 { 2639 vtime = _asl_time_string(tfmt, v, nano); 2640 } 2641 2642 level = 7; 2643 if (asl_msg_lookup(msg, ASL_KEY_LEVEL, &vlevel, NULL) == 0) 2644 { 2645 if (vlevel != NULL) level = atoi(vlevel); 2646 } 2647 2648 if (asl_msg_lookup(msg, ASL_KEY_HOST, &vhost, NULL) == 0) 2649 { 2650 if (vhost == NULL) vhost = "unknown"; 2651 } 2652 2653 if (asl_msg_lookup(msg, ASL_KEY_SENDER, &vsender, NULL) == 0) 2654 { 2655 if (vsender == NULL) vsender = "unknown"; 2656 } 2657 2658 asl_msg_lookup(msg, ASL_KEY_PID, &vpid, NULL); 2659 asl_msg_lookup(msg, ASL_KEY_MSG, &vmessage, NULL); 2660 asl_msg_lookup(msg, ASL_KEY_REF_PROC, &vrefproc, NULL); 2661 asl_msg_lookup(msg, ASL_KEY_REF_PID, &vrefpid, NULL); 2662 2663 /* COMMON */ 2664 str = asl_string_new(text_encoding); 2665 if (str == NULL) return NULL; 2666 2667 if (vtime != NULL) 2668 { 2669 asl_string_append(str, vtime); 2670 free(vtime); 2671 } 2672 else 2673 { 2674 asl_string_append_char_no_encoding(str, '0'); 2675 } 2676 2677 asl_string_append_char_no_encoding(str, ' '); 2678 asl_string_append(str, vhost); 2679 asl_string_append_char_no_encoding(str, ' '); 2680 asl_string_append(str, vsender); 2681 2682 if ((vpid != NULL) && (strcmp(vpid, "-1"))) 2683 { 2684 asl_string_append_char_no_encoding(str, '['); 2685 asl_string_append(str, vpid); 2686 asl_string_append_char_no_encoding(str, ']'); 2687 } 2688 2689 if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_no_encoding(str, " ("); 2690 2691 if (vrefproc != NULL) asl_string_append(str, vrefproc); 2692 if (vrefpid != NULL) 2693 { 2694 asl_string_append_char_no_encoding(str, '['); 2695 asl_string_append(str, vrefpid); 2696 asl_string_append_char_no_encoding(str, ']'); 2697 } 2698 2699 if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_char_no_encoding(str, ')'); 2700 2701 if (mf == MFMT_STD) 2702 { 2703 asl_string_append_no_encoding(str, " <"); 2704 asl_string_append(str, _asl_level_string(level)); 2705 asl_string_append_char_no_encoding(str, '>'); 2706 } 2707 2708 asl_string_append_no_encoding(str, ": "); 2709 if (vmessage != NULL) asl_string_append(str, vmessage); 2710 asl_string_append_char_no_encoding(str, '\n'); 2711 2712 *len = asl_string_length(str); 2713 out = asl_string_release_return_bytes(str); 2714 return out; 2715 } 2716 2717 if (mf == MFMT_XML) 2718 { 2719 str = asl_string_new(text_encoding); 2720 if (str == NULL) return NULL; 2721 2722 asl_string_append_char_no_encoding(str, '\t'); 2723 asl_string_append_no_encoding(str, "<dict>"); 2724 asl_string_append_char_no_encoding(str, '\n'); 2725 2726 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL)) 2727 { 2728 if (asl_is_utf8(key) == 1) 2729 { 2730 asl_string_append_xml_tag(str, "key", key); 2731 if (!strcmp(key, ASL_KEY_TIME)) 2732 { 2733 vtime = _asl_time_string(tfmt, val, nano); 2734 if (vtime != NULL) 2735 { 2736 asl_string_append_xml_tag(str, "string", vtime); 2737 free(vtime); 2738 } 2739 else 2740 { 2741 asl_string_append_xml_tag(str, "string", "0"); 2742 } 2743 } 2744 else 2745 { 2746 if (asl_is_utf8(val) == 1) asl_string_append_xml_tag(str, "string", val); 2747 else 2748 { 2749 b64 = asl_b64_encode((uint8_t *)val, strlen(val)); 2750 asl_string_append_xml_tag(str, "data", (char *)b64); 2751 free(b64); 2752 } 2753 } 2754 } 2755 } 2756 2757 asl_string_append_char_no_encoding(str, '\t'); 2758 asl_string_append_no_encoding(str, "</dict>"); 2759 asl_string_append_char_no_encoding(str, '\n'); 2760 2761 *len = asl_string_length(str); 2762 out = asl_string_release_return_bytes(str); 2763 return out; 2764 } 2765 2766 /* 2767 * Custom format 2768 * The format string may contain arbitrary characters. 2769 * Keys are identified by $Key or $(Key). The value for 2770 * that key is substituted. If there are alterate formats 2771 * for the value (for example a time may be formatted as 2772 * raw seconds, in UTC, or a local timezone), then the 2773 * key may be $((Key)(Format)). "\$" prints a plain "$". 2774 */ 2775 2776 str = asl_string_new(text_encoding); 2777 if (str == NULL) return NULL; 2778 2779 /* 2780 * We need enough space to copy any keys found in mfmt. 2781 * The key obviously can't be longer than strlen(mfmt), 2782 * in fact, keys must be shorter, since there's at least a '$' 2783 * in front of the key, so we allocate a buffer with strlen(mfmt). 2784 * If strlen(mfmt) <= sizeof(skey), we use skey to avoid a malloc. 2785 */ 2786 2787 x = strlen(mfmt); 2788 if (x <= sizeof(skey)) 2789 { 2790 k = skey; 2791 } 2792 else 2793 { 2794 k = malloc(x); 2795 if (k == NULL) return NULL; 2796 } 2797 2798 cursor = 0; 2799 2800 for (i = 0; mfmt[i] != '\0'; i++) 2801 { 2802 if (mfmt[i] == '$') 2803 { 2804 paren = 0; 2805 2806 /* scan key, (key) or ((key)(format)) */ 2807 for (j = i + 1; mfmt[j] != 0; j++) 2808 { 2809 if (mfmt[j] == '(') 2810 { 2811 paren++; 2812 } 2813 else if (mfmt[j] == ')') 2814 { 2815 if (paren > 0) paren--; 2816 if (paren == 0) 2817 { 2818 j++; 2819 break; 2820 } 2821 } 2822 else if (((mfmt[j] == ' ') || (mfmt[j] == '\t')) && (paren == 0)) break; 2823 } 2824 2825 /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */ 2826 l = j - (i + 1); 2827 memcpy(k, mfmt+i+1, l); 2828 k[l] = '\0'; 2829 _asl_string_append_value_for_key_format(str, msg, k, tfmt); 2830 2831 i = j - 1; 2832 continue; 2833 } 2834 2835 if (mfmt[i] == '\\') 2836 { 2837 i++; 2838 if (mfmt[i] == '$') asl_string_append_char_no_encoding(str, '$'); 2839 else if (mfmt[i] == 'e') asl_string_append_char_no_encoding(str, '\e'); 2840 else if (mfmt[i] == 's') asl_string_append_char_no_encoding(str, ' '); 2841 else if (mfmt[i] == 'a') asl_string_append_char_no_encoding(str, '\a'); 2842 else if (mfmt[i] == 'b') asl_string_append_char_no_encoding(str, '\b'); 2843 else if (mfmt[i] == 'f') asl_string_append_char_no_encoding(str, '\f'); 2844 else if (mfmt[i] == 'n') asl_string_append_char_no_encoding(str, '\n'); 2845 else if (mfmt[i] == 'r') asl_string_append_char_no_encoding(str, '\r'); 2846 else if (mfmt[i] == 't') asl_string_append_char_no_encoding(str, '\t'); 2847 else if (mfmt[i] == 'v') asl_string_append_char_no_encoding(str, '\v'); 2848 else if (mfmt[i] == '\'') asl_string_append_char_no_encoding(str, '\''); 2849 else if (mfmt[i] == '\\') asl_string_append_char_no_encoding(str, '\\'); 2850 else if (isdigit(mfmt[i])) 2851 { 2852 oval = mfmt[i] - '0'; 2853 if (isdigit(mfmt[i+1])) 2854 { 2855 i++; 2856 oval = (oval * 8) + (mfmt[i] - '0'); 2857 if (isdigit(mfmt[i+1])) 2858 { 2859 i++; 2860 oval = (oval * 8) + (mfmt[i] - '0'); 2861 } 2862 } 2863 c = oval; 2864 asl_string_append_char_no_encoding(str, c); 2865 } 2866 continue; 2867 } 2868 2869 if (mfmt[i] == '\0') break; 2870 asl_string_append_char_no_encoding(str, mfmt[i]); 2871 } 2872 2873 if (k != skey) free(k); 2874 2875 asl_string_append_char_no_encoding(str, '\n'); 2876 2877 *len = asl_string_length(str); 2878 out = asl_string_release_return_bytes(str); 2879 return out; 2880} 2881 2882#pragma mark - 2883#pragma mark asl_object support 2884 2885static asl_object_private_t * 2886_jump_alloc(uint32_t type) 2887{ 2888 return (asl_object_private_t *)asl_msg_new(type); 2889} 2890 2891static void 2892_jump_dealloc(asl_object_private_t *obj) 2893{ 2894 asl_msg_t *msg = (asl_msg_t *)obj; 2895 while (msg != NULL) 2896 { 2897 asl_msg_t *next = msg->next; 2898 _asl_msg_free_page(msg); 2899 msg = next; 2900 } 2901} 2902 2903static int 2904_jump_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op) 2905{ 2906 uint32_t op32 = op; 2907 int status = asl_msg_set_key_val_op((asl_msg_t *)obj, key, val, op32); 2908 return (status == ASL_STATUS_OK) ? 0 : -1; 2909} 2910 2911static void 2912_jump_unset_key(asl_object_private_t *obj, const char *key) 2913{ 2914 asl_msg_unset((asl_msg_t *)obj, key); 2915} 2916 2917static int 2918_jump_get_val_op_for_key(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op) 2919{ 2920 return asl_msg_lookup((asl_msg_t *)obj, key, val, op); 2921} 2922 2923static int 2924_jump_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op) 2925{ 2926 uint32_t slot = IndexNull; 2927 asl_msg_t *page = NULL; 2928 2929 if (0 != _asl_msg_resolve_index((asl_msg_t *)obj, n, &page, &slot)) return -1; 2930 2931 if (key != NULL) *key = _asl_msg_slot_key(page, slot); 2932 if (val != NULL) *val = _asl_msg_slot_val(page, slot); 2933 if (op != NULL) *op = page->op[slot]; 2934 return 0; 2935} 2936 2937static size_t 2938_jump_count(asl_object_private_t *obj) 2939{ 2940 size_t count = asl_msg_count((asl_msg_t *)obj); 2941 return count; 2942} 2943 2944static void 2945_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) 2946{ 2947 int type = asl_get_type((asl_object_t)newobj); 2948 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; 2949 2950 asl_msg_merge((asl_msg_t *)obj, (asl_msg_t *)newobj); 2951} 2952 2953static void 2954_jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj) 2955{ 2956 if (obj == NULL) return; 2957 2958 int type = asl_get_type((asl_object_t)newobj); 2959 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; 2960 2961 asl_msg_replace((asl_msg_t *)obj, (asl_msg_t *)newobj); 2962} 2963 2964static asl_object_private_t * 2965_jump_search(asl_object_private_t *obj, asl_object_private_t *query) 2966{ 2967 if (obj == NULL) return NULL; 2968 2969 if (query == NULL) 2970 { 2971 /* NULL matches any message */ 2972 asl_msg_list_t *out = asl_msg_list_new(); 2973 asl_msg_list_append(out, obj); 2974 return (asl_object_private_t *)out; 2975 } 2976 2977 if ((query->asl_type != ASL_TYPE_MSG) && (query->asl_type != ASL_TYPE_QUERY)) return NULL; 2978 2979 if (asl_msg_cmp((asl_msg_t *)obj, (asl_msg_t *)query) == 1) 2980 { 2981 asl_msg_list_t *out = asl_msg_list_new(); 2982 asl_msg_list_append(out, obj); 2983 return (asl_object_private_t *)out; 2984 } 2985 2986 return NULL; 2987} 2988 2989static asl_object_private_t * 2990_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) 2991{ 2992 if (obj == NULL) return NULL; 2993 2994 if (qlist == NULL) 2995 { 2996 /* NULL matches any message */ 2997 asl_msg_list_t *out = asl_msg_list_new(); 2998 asl_msg_list_append(out, obj); 2999 return (asl_object_private_t *)out; 3000 } 3001 3002 if (asl_msg_cmp_list((asl_msg_t *)obj, (asl_msg_list_t *)qlist) == 0) return NULL; 3003 3004 asl_msg_list_t *out = asl_msg_list_new(); 3005 asl_msg_list_append(out, obj); 3006 return (asl_object_private_t *)out; 3007} 3008 3009 3010__private_extern__ const asl_jump_table_t * 3011asl_msg_jump_table() 3012{ 3013 static const asl_jump_table_t jump = 3014 { 3015 .alloc = &_jump_alloc, 3016 .dealloc = &_jump_dealloc, 3017 .set_key_val_op = &_jump_set_key_val_op, 3018 .unset_key = &_jump_unset_key, 3019 .get_val_op_for_key = &_jump_get_val_op_for_key, 3020 .get_key_val_op_at_index = &_jump_get_key_val_op_at_index, 3021 .count = &_jump_count, 3022 .next = NULL, 3023 .prev = NULL, 3024 .get_object_at_index = NULL, 3025 .set_iteration_index = NULL, 3026 .remove_object_at_index = NULL, 3027 .append = &_jump_append, 3028 .prepend = &_jump_prepend, 3029 .search = &_jump_search, 3030 .match = &_jump_match 3031 }; 3032 3033 return &jump; 3034} 3035