2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
38 #include <asl_object.h>
39 #include <asl_private.h>
41 #include <asl_client.h>
42 #include <sys/types.h>
43 #include <libkern/OSAtomic.h>
45 #include <asl_msg_list.h>
60 #define SEC_PER_HOUR 3600
64 #define forever for(;;)
66 #ifndef ASL_QUERY_OP_FALSE
67 #define ASL_QUERY_OP_FALSE 0
70 #define AUX_0_TIME 0x00000001
71 #define AUX_0_TIME_NSEC 0x00000002
72 #define AUX_0_HOST 0x00000004
73 #define AUX_0_SENDER 0x00000008
74 #define AUX_0_FACILITY 0x00000010
75 #define AUX_0_PID 0x00000020
76 #define AUX_0_UID 0x00000040
77 #define AUX_0_GID 0x00000080
78 #define AUX_0_MSG 0x00000100
79 #define AUX_0_OPTION 0x00000200
80 #define AUX_0_LEVEL 0x00000400
83 int asl_is_utf8(const char *str
);
84 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
86 void _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t
*msg
);
89 #pragma mark standard message keys
91 static const char *ASLStandardKey
[] =
114 static const char *MTStandardKey
[] =
116 "com.apple.message.domain",
117 "com.apple.message.domain_scope",
118 "com.apple.message.result",
119 "com.apple.message.signature",
120 "com.apple.message.signature2",
121 "com.apple.message.signature3",
122 "com.apple.message.success",
123 "com.apple.message.uuid",
124 "com.apple.message.value",
125 "com.apple.message.value2",
126 "com.apple.message.value3",
127 "com.apple.message.value4",
128 "com.apple.message.value5"
132 _asl_msg_std_key(const char *s
, uint32_t len
)
134 if ((len
> 18) && (streq_len(s
, "com.apple.message.", 18)))
136 if (streq(s
+ 18, "domain")) return ASL_MT_KEY_DOMAIN
;
137 else if (streq(s
+ 18, "domain_scope")) return ASL_MT_KEY_SCOPE
;
138 else if (streq(s
+ 18, "result")) return ASL_MT_KEY_RESULT
;
139 else if (streq(s
+ 18, "signature")) return ASL_MT_KEY_SIG
;
140 else if (streq(s
+ 18, "signature2")) return ASL_MT_KEY_SIG2
;
141 else if (streq(s
+ 18, "signature3")) return ASL_MT_KEY_SIG3
;
142 else if (streq(s
+ 18, "success")) return ASL_MT_KEY_SUCCESS
;
143 else if (streq(s
+ 18, "uuid")) return ASL_MT_KEY_UUID
;
144 else if (streq(s
+ 18, "value")) return ASL_MT_KEY_VAL
;
145 else if (streq(s
+ 18, "value2")) return ASL_MT_KEY_VAL2
;
146 else if (streq(s
+ 18, "value3")) return ASL_MT_KEY_VAL3
;
147 else if (streq(s
+ 18, "value4")) return ASL_MT_KEY_VAL4
;
148 else if (streq(s
+ 18, "value5")) return ASL_MT_KEY_VAL5
;
157 if streq(s
, ASL_KEY_PID
) return ASL_STD_KEY_PID
;
158 else if streq(s
, ASL_KEY_UID
) return ASL_STD_KEY_UID
;
159 else if streq(s
, ASL_KEY_GID
) return ASL_STD_KEY_GID
;
163 if streq(s
, ASL_KEY_TIME
) return ASL_STD_KEY_TIME
;
164 else if streq(s
, ASL_KEY_HOST
) return ASL_STD_KEY_HOST
;
168 if streq(s
, ASL_KEY_LEVEL
) return ASL_STD_KEY_LEVEL
;
172 if streq(s
, ASL_KEY_SENDER
) return ASL_STD_KEY_SENDER
;
173 else if streq(s
, ASL_KEY_REF_PID
) return ASL_STD_KEY_REF_PID
;
177 if streq(s
, ASL_KEY_MSG
) return ASL_STD_KEY_MESSAGE
;
178 else if streq(s
, ASL_KEY_SESSION
) return ASL_STD_KEY_SESSION
;
179 else if streq(s
, ASL_KEY_READ_UID
) return ASL_STD_KEY_READ_UID
;
180 else if streq(s
, ASL_KEY_READ_GID
) return ASL_STD_KEY_READ_GID
;
181 else if streq(s
, ASL_KEY_REF_PROC
) return ASL_STD_KEY_REF_PROC
;
185 if streq(s
, ASL_KEY_FACILITY
) return ASL_STD_KEY_FACILITY
;
189 if streq(s
, ASL_KEY_OPTION
) return ASL_STD_KEY_OPTION
;
193 if streq(s
, ASL_KEY_TIME_NSEC
) return ASL_STD_KEY_NANO
;
197 if streq(s
, ASL_KEY_MSG_ID
) return ASL_STD_KEY_MSG_ID
;
201 if streq(s
, ASL_KEY_EXPIRE_TIME
) return ASL_STD_KEY_EXPIRE
;
205 if streq(s
, ASL_KEY_FREE_NOTE
) return ASL_STD_KEY_FREE_NOTE
;
220 _slot_count(asl_msg_t
*m
)
222 if (m
== NULL
) return 0;
223 if (m
->asl_type
== ASL_TYPE_MSG
) return ASL_MSG_KVO_MSG_SLOTS
;
224 if (m
->asl_type
== ASL_TYPE_QUERY
) return ASL_MSG_KVO_QUERY_SLOTS
;
230 _get_slot_key(asl_msg_t
*m
, uint32_t slot
)
232 if (m
== NULL
) return 0;
234 if (m
->asl_type
== ASL_TYPE_MSG
)
236 if (slot
< ASL_MSG_KVO_MSG_SLOTS
) return m
->kvo
[slot
];
240 if (m
->asl_type
== ASL_TYPE_QUERY
)
242 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot
];
251 _set_slot_key(asl_msg_t
*m
, uint32_t slot
, uint16_t x
)
253 if (m
== NULL
) return;
255 if (m
->asl_type
== ASL_TYPE_MSG
)
257 if (slot
< ASL_MSG_KVO_MSG_SLOTS
) m
->kvo
[slot
] = x
;
261 if (m
->asl_type
== ASL_TYPE_QUERY
)
263 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot
] = x
;
270 _get_slot_val(asl_msg_t
*m
, uint32_t slot
)
272 if (m
== NULL
) return 0;
273 if (m
->asl_type
== ASL_TYPE_MSG
)
275 if (slot
< ASL_MSG_KVO_MSG_SLOTS
) return m
->kvo
[slot
+ ASL_MSG_KVO_MSG_SLOTS
];
279 if (m
->asl_type
== ASL_TYPE_QUERY
)
281 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot
+ ASL_MSG_KVO_QUERY_SLOTS
];
289 _set_slot_val(asl_msg_t
*m
, uint32_t slot
, uint16_t x
)
291 if (m
== NULL
) return;
293 if (m
->asl_type
== ASL_TYPE_MSG
)
295 if (slot
< ASL_MSG_KVO_MSG_SLOTS
) m
->kvo
[slot
+ ASL_MSG_KVO_MSG_SLOTS
] = x
;
299 if (m
->asl_type
== ASL_TYPE_QUERY
)
301 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot
+ ASL_MSG_KVO_QUERY_SLOTS
] = x
;
307 _get_slot_op(asl_msg_t
*m
, uint32_t slot
)
309 if (m
== NULL
) return 0;
311 if (m
->asl_type
== ASL_TYPE_QUERY
)
313 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot
+ (ASL_MSG_KVO_QUERY_SLOTS
* 2)];
321 _set_slot_op(asl_msg_t
*m
, uint32_t slot
, uint16_t x
)
323 if (m
== NULL
) return;
325 if (m
->asl_type
== ASL_TYPE_QUERY
)
327 if (slot
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot
+ (ASL_MSG_KVO_QUERY_SLOTS
* 2)] = x
;
332 _asl_msg_make_page(uint32_t type
)
335 asl_msg_t
*out
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
336 if (out
== NULL
) return NULL
;
338 if (type
== ASL_TYPE_MSG
) n
= ASL_MSG_KVO_MSG_SLOTS
* 2;
339 else if (type
== ASL_TYPE_QUERY
) n
= ASL_MSG_KVO_QUERY_SLOTS
* 2;
341 for (i
= 0; i
< n
; i
++) out
->kvo
[i
] = ASL_MSG_SLOT_FREE
;
343 out
->mem_size
= sizeof(asl_msg_t
);
344 out
->asl_type
= type
;
350 asl_msg_retain(asl_msg_t
*msg
)
352 if (msg
== NULL
) return NULL
;
353 asl_retain((asl_object_t
)msg
);
358 asl_msg_release(asl_msg_t
*msg
)
360 if (msg
== NULL
) return;
361 asl_release((asl_object_t
)msg
);
365 _asl_msg_slot_key(asl_msg_t
*page
, uint32_t slot
)
370 if (page
== NULL
) return NULL
;
372 if ((page
->asl_type
== ASL_TYPE_MSG
) && (slot
>= ASL_MSG_KVO_MSG_SLOTS
)) return NULL
;
373 else if ((page
->asl_type
== ASL_TYPE_QUERY
) && (slot
>= ASL_MSG_KVO_QUERY_SLOTS
)) return NULL
;
375 k
= _get_slot_key(page
, slot
);
377 if (k
== ASL_MSG_SLOT_FREE
) return NULL
;
379 switch (k
& ASL_MSG_KV_MASK
)
381 case ASL_MSG_KV_INLINE
:
383 return page
->data
+ k
;
385 case ASL_MSG_KV_DICT
:
387 if ((k
> ASL_STD_KEY_BASE
) && (k
<= ASL_STD_KEY_LAST
))
389 x
= k
- ASL_STD_KEY_BASE
- 1;
390 return ASLStandardKey
[x
];
392 else if ((k
> ASL_MT_KEY_BASE
) && (k
<= ASL_MT_KEY_LAST
))
394 x
= k
- ASL_MT_KEY_BASE
- 1;
395 return MTStandardKey
[x
];
400 case ASL_MSG_KV_EXTERN
:
402 x
= k
& ASL_MSG_OFFSET_MASK
;
403 memcpy(&out
, page
->data
+ x
, sizeof(char *));
412 _asl_msg_slot_val(asl_msg_t
*page
, uint32_t slot
)
417 if (page
== NULL
) return NULL
;
419 if ((page
->asl_type
== ASL_TYPE_MSG
) && (slot
>= ASL_MSG_KVO_MSG_SLOTS
)) return NULL
;
420 else if ((page
->asl_type
== ASL_TYPE_QUERY
) && (slot
>= ASL_MSG_KVO_QUERY_SLOTS
)) return NULL
;
422 v
= _get_slot_val(page
, slot
);
424 if (v
== ASL_MSG_SLOT_FREE
) return NULL
;
426 type
= v
& ASL_MSG_KV_MASK
;
428 if (type
== ASL_MSG_KV_INLINE
)
430 return page
->data
+ v
;
432 else if (type
== ASL_MSG_KV_EXTERN
)
434 x
= v
& ASL_MSG_OFFSET_MASK
;
435 memcpy(&out
, page
->data
+ x
, sizeof(char *));
443 * asl_new: create a new log message.
446 asl_msg_new(uint32_t type
)
450 out
= _asl_msg_make_page(type
);
451 if (out
== NULL
) return NULL
;
453 out
->asl_type
= type
;
460 _asl_msg_free_page(asl_msg_t
*page
)
465 if (page
== NULL
) return;
467 mslots
= _slot_count(page
);
469 for (i
= 0; i
< mslots
; i
++)
471 uint16_t k
= _get_slot_key(page
, i
);
472 uint16_t v
= _get_slot_val(page
, i
);
474 if (k
== ASL_STD_KEY_FREE_NOTE
)
476 const char *x
= _asl_msg_slot_val(page
, i
);
477 if (x
!= NULL
) notify_post(x
);
480 if ((k
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
482 memcpy(&p
, page
->data
+ (k
& ASL_MSG_OFFSET_MASK
), sizeof(char *));
486 if ((v
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
488 memcpy(&p
, page
->data
+ (v
& ASL_MSG_OFFSET_MASK
), sizeof(char *));
497 asl_msg_type(asl_msg_t
*msg
)
499 if (msg
== NULL
) return 0;
500 return msg
->asl_type
;
504 asl_msg_count(asl_msg_t
*msg
)
510 for (; msg
!= NULL
; msg
= msg
->next
) total
+= msg
->count
;
515 _asl_msg_dump_kv(FILE *f
, asl_msg_t
*msg
, uint16_t x
)
517 if (x
== ASL_MSG_SLOT_FREE
)
519 fprintf(f
, "-free-");
523 if ((x
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
)
527 case ASL_STD_KEY_TIME
: fprintf(f
, "(dict: Time)"); return;
528 case ASL_STD_KEY_NANO
: fprintf(f
, "(dict: Nano)"); return;
529 case ASL_STD_KEY_HOST
: fprintf(f
, "(dict: Host)"); return;
530 case ASL_STD_KEY_SENDER
: fprintf(f
, "(dict: Sender)"); return;
531 case ASL_STD_KEY_FACILITY
: fprintf(f
, "(dict: Facility)"); return;
532 case ASL_STD_KEY_PID
: fprintf(f
, "(dict: PID)"); return;
533 case ASL_STD_KEY_UID
: fprintf(f
, "(dict: UID)"); return;
534 case ASL_STD_KEY_GID
: fprintf(f
, "(dict: GID)"); return;
535 case ASL_STD_KEY_LEVEL
: fprintf(f
, "(dict: Level)"); return;
536 case ASL_STD_KEY_MESSAGE
: fprintf(f
, "(dict: Message)"); return;
537 case ASL_STD_KEY_READ_UID
: fprintf(f
, "(dict: ReadUID)"); return;
538 case ASL_STD_KEY_READ_GID
: fprintf(f
, "(dict: ReadGID)"); return;
539 case ASL_STD_KEY_SESSION
: fprintf(f
, "(dict: Session)"); return;
540 case ASL_STD_KEY_REF_PID
: fprintf(f
, "(dict: PID)"); return;
541 case ASL_STD_KEY_REF_PROC
: fprintf(f
, "(dict: RefProc)"); return;
542 case ASL_STD_KEY_MSG_ID
: fprintf(f
, "(dict: ASLMessageID)"); return;
543 case ASL_STD_KEY_EXPIRE
: fprintf(f
, "(dict: Expire)"); return;
544 case ASL_STD_KEY_OPTION
: fprintf(f
, "(dict: ASLOption)"); return;
545 case ASL_MT_KEY_DOMAIN
: fprintf(f
, "(dict: com.apple.message.domain)"); return;
546 case ASL_MT_KEY_SCOPE
: fprintf(f
, "(dict: com.apple.message.domain_scope)"); return;
547 case ASL_MT_KEY_RESULT
: fprintf(f
, "(dict: com.apple.message.result)"); return;
548 case ASL_MT_KEY_SIG
: fprintf(f
, "(dict: com.apple.message.signature)"); return;
549 case ASL_MT_KEY_SIG2
: fprintf(f
, "(dict: com.apple.message.signature2)"); return;
550 case ASL_MT_KEY_SIG3
: fprintf(f
, "(dict: com.apple.message.signature3)"); return;
551 case ASL_MT_KEY_SUCCESS
: fprintf(f
, "(dict: com.apple.message.success)"); return;
552 case ASL_MT_KEY_UUID
: fprintf(f
, "(dict: com.apple.message.uuid)"); return;
553 case ASL_MT_KEY_VAL
: fprintf(f
, "(dict: com.apple.message.value)"); return;
554 case ASL_MT_KEY_VAL2
: fprintf(f
, "(dict: com.apple.message.value2)"); return;
555 case ASL_MT_KEY_VAL3
: fprintf(f
, "(dict: com.apple.message.value3)"); return;
556 case ASL_MT_KEY_VAL4
: fprintf(f
, "(dict: com.apple.message.value4)"); return;
557 case ASL_MT_KEY_VAL5
: fprintf(f
, "(dict: com.apple.message.value5)"); return;
560 fprintf(f
, "(dict: -unknown-)");
564 if ((x
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
567 size_t z
= x
& ASL_MSG_OFFSET_MASK
;
568 memcpy(&c
, msg
->data
+ z
, sizeof(char *));
569 fprintf(f
, "(extern: %s)", c
);
573 fprintf(f
, "%s", msg
->data
+ x
);
577 _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t
*msg
)
579 uint32_t i
, mslots
, page1
= 1;
581 if (f
== NULL
) return;
584 fprintf(f
, "asl_msg %s: NULL\n", comment
);
588 mslots
= _slot_count(msg
);
594 fprintf(f
, "asl_msg %s: %p\n", comment
, msg
);
595 fprintf(f
, " refcount: %u\n", msg
->refcount
);
596 fprintf(f
, " asl_type: %u\n", msg
->asl_type
);
601 fprintf(f
, " page: %p\n", msg
);
604 fprintf(f
, " count: %u\n", msg
->count
);
605 fprintf(f
, " data_size: %u\n", msg
->data_size
);
606 fprintf(f
, " mem_size: %llu\n", msg
->mem_size
);
607 fprintf(f
, " next: %p\n", msg
->next
);
609 for (i
= 0; i
< mslots
; i
++)
611 fprintf(f
, " slot[%d]: ", i
);
612 _asl_msg_dump_kv(f
, msg
, _get_slot_key(msg
, i
));
614 _asl_msg_dump_kv(f
, msg
, _get_slot_val(msg
, i
));
615 if (msg
->asl_type
== ASL_TYPE_QUERY
) fprintf(f
, " 0x%04x\n", _get_slot_op(msg
, i
));
623 #pragma mark fetching contents
626 * Find the slot and page for an input key.
629 _asl_msg_index(asl_msg_t
*msg
, const char *key
, uint32_t *oslot
, asl_msg_t
**opage
)
631 uint32_t i
, len
, slot
, mslots
;
636 if (msg
== NULL
) return IndexNull
;
637 if (key
== NULL
) return IndexNull
;
641 mslots
= _slot_count(msg
);
643 if (oslot
!= NULL
) *oslot
= slot
;
646 if (opage
!= NULL
) *opage
= page
;
649 kx
= _asl_msg_std_key(key
, len
);
653 if (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
)
657 if (_get_slot_key(page
, slot
) == kx
) return i
;
659 else if ((_get_slot_key(page
, slot
) & ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
)
661 /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */
663 else if ((_get_slot_key(page
, slot
) & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
665 memcpy(&kp
, page
->data
+ (_get_slot_key(page
, slot
) & ASL_MSG_OFFSET_MASK
), sizeof(char *));
666 if (streq(key
, kp
)) return i
;
670 kp
= page
->data
+ _get_slot_key(page
, slot
);
671 if (streq(key
, kp
)) return i
;
677 if (oslot
!= NULL
) *oslot
= slot
;
681 if (page
->next
== NULL
) return IndexNull
;
684 if (oslot
!= NULL
) *oslot
= slot
;
687 if (opage
!= NULL
) *opage
= page
;
695 * Find page and slot for an "index".
698 _asl_msg_resolve_index(asl_msg_t
*msg
, uint32_t n
, asl_msg_t
**page
, uint32_t *slot
)
700 uint32_t i
, sx
, mslots
;
703 if (msg
== NULL
) return -1;
708 mslots
= _slot_count(msg
);
713 for (px
= msg
; px
!= NULL
; px
= px
->next
)
715 if (n
> (sx
+ px
->count
))
724 for (i
= 0; i
< mslots
; i
++)
726 if (px
->kvo
[i
] != ASL_MSG_SLOT_FREE
)
743 * asl_msg_fetch: iterate over entries
744 * initial value of n should be 0. Subseqent calls should use the last
745 * returned value. Returns IndexNull when there are no more entries
746 * Sets the pointers for the next key, value, and op in the msg.
747 * The iterator encodes a page number and a slot number.
751 asl_msg_fetch(asl_msg_t
*msg
, uint32_t x
, const char **keyout
, const char **valout
, uint16_t *opout
)
753 uint32_t p
, xpn
, xsn
, mslots
;
754 asl_msg_t
*page
= NULL
;
756 if (msg
== NULL
) return IndexNull
;
758 mslots
= _slot_count(msg
);
761 xpn
= x
& 0x00ffffff;
763 /* slot number 0xff means we have run out entries */
764 if (xsn
== 0x000000ff) return IndexNull
;
767 for (p
= 0; p
< xpn
; p
++)
770 if (page
== NULL
) return IndexNull
;
773 if (keyout
!= NULL
) *keyout
= _asl_msg_slot_key(page
, xsn
);
774 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, xsn
);
775 if (opout
!= NULL
) *opout
= _get_slot_op(page
, xsn
);
777 /* advance to the next slot */
784 if (page
->next
== NULL
) return 0xff000000;
790 if (page
->kvo
[xsn
] != ASL_MSG_SLOT_FREE
) return ((xsn
<< 24) | xpn
);
797 asl_msg_lookup(asl_msg_t
*msg
, const char *key
, const char **valout
, uint16_t *opout
)
802 if (msg
== NULL
) return -1;
803 if (valout
!= NULL
) *valout
= NULL
;
804 if (opout
!= NULL
) *opout
= 0;
809 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
810 if (i
== IndexNull
) return -1;
812 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, slot
);
813 if (opout
!= NULL
) *opout
= _get_slot_op(page
, slot
);
819 asl_msg_get_val_for_key(asl_msg_t
*msg
, const char *key
)
824 if (msg
== NULL
) return NULL
;
829 if (_asl_msg_index(msg
, key
, &slot
, &page
) == IndexNull
) return NULL
;
831 return _asl_msg_slot_val(page
, slot
);
835 asl_msg_key(asl_msg_t
*msg
, uint32_t n
)
837 uint32_t slot
, i
, mslots
;
840 if (msg
== NULL
) return NULL
;
842 mslots
= _slot_count(msg
);
845 for (page
= msg
; page
!= NULL
; page
= page
->next
)
847 for (slot
= 0; slot
< mslots
; slot
++)
849 if (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
)
851 if (i
== n
) return _asl_msg_slot_key(page
, slot
);
861 #pragma mark adding and replacing contents
864 _asl_msg_new_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
866 uint32_t slot
, keylen
, vallen
, total
, mslots
;
868 uint16_t kx
, k
, v
, o
;
869 asl_msg_t
*page
, *last
;
870 char *extkey
, *extval
;
872 if (msg
== NULL
) return -1;
873 if (key
== NULL
) return -1;
875 mslots
= _slot_count(msg
);
881 keylen
= strlen(key
);
883 kx
= _asl_msg_std_key(key
, keylen
);
885 if (kx
== 0) keylen
++;
893 vallen
= strlen(val
) + 1;
898 /* check if one or both of key and value must be "external" (in its own malloced space) */
899 if (keylen
> ASL_MSG_PAGE_DATA_SIZE
)
901 extkey
= strdup(key
);
902 keylen
= sizeof(char *);
905 if (vallen
> ASL_MSG_PAGE_DATA_SIZE
)
907 extval
= strdup(val
);
908 vallen
= sizeof(char *);
911 total
= keylen
+ vallen
;
912 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extval
== NULL
) && (keylen
> 0))
914 extval
= strdup(val
);
915 vallen
= sizeof(char *);
916 total
= keylen
+ vallen
;
919 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extkey
== NULL
))
921 extkey
= strdup(key
);
922 keylen
= sizeof(char *);
923 total
= keylen
+ vallen
;
926 if (total
> ASL_MSG_PAGE_DATA_SIZE
)
928 /* can't happen, but... */
929 if (extkey
!= NULL
) free(extkey
);
930 if (extval
!= NULL
) free(extval
);
934 /* find a page with space for the key and value and a free slot*/
938 for (page
= msg
; page
!= NULL
; page
= page
->next
)
942 if (total
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
944 /* check for a free slot */
945 for (slot
= 0; (slot
< mslots
) && (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
); slot
++);
946 if (slot
< mslots
) break;
952 /* allocate a new page and attach it */
953 page
= _asl_msg_make_page(msg
->asl_type
);
956 if (extkey
!= NULL
) free(extkey
);
957 if (extval
!= NULL
) free(extval
);
965 /* copy key or external key pointer into page data */
970 else if (extkey
== NULL
)
973 memcpy(page
->data
+ page
->data_size
, key
, keylen
);
977 k
= page
->data_size
| ASL_MSG_KV_EXTERN
;
978 memcpy(page
->data
+ page
->data_size
, &extkey
, keylen
);
979 page
->mem_size
+= klen
;
982 _set_slot_key(page
, slot
, k
);
983 page
->data_size
+= keylen
;
985 /* copy val or external val pointer into page data */
987 v
= ASL_MSG_SLOT_FREE
;
994 memcpy(page
->data
+ page
->data_size
, val
, vallen
);
998 v
= page
->data_size
| ASL_MSG_KV_EXTERN
;
999 memcpy(page
->data
+ page
->data_size
, &extval
, vallen
);
1000 page
->mem_size
+= vlen
;
1003 _set_slot_val(page
, slot
, v
);
1004 page
->data_size
+= vallen
;
1008 _set_slot_op(page
, slot
, o
);
1010 /* update page count */
1017 * Most of the code in asl_msg_set_key_val_op is concerned with trying to re-use
1018 * space in an asl_msg_t page when given a new value for an existing key.
1019 * If the key is new, we just call _asl_msg_new_key_val_op.
1021 * Note that queries can have duplicate keys, so for ASL_TYPE_QUERY we just
1022 * call through to _asl_msg_new_key_val_op.
1025 _asl_msg_set_kvo(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
1027 uint32_t i
, slot
, mslots
, newexternal
;
1029 uint32_t intvallen
, extvallen
, newvallen
;
1030 char *intval
, *extval
, *newval
;
1033 if (msg
== NULL
) return -1;
1034 if (key
== NULL
) return -1;
1036 mslots
= _slot_count(msg
);
1043 if ((msg
->asl_type
== ASL_TYPE_QUERY
) || (IndexNull
== _asl_msg_index(msg
, key
, &slot
, &page
)))
1046 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
1055 v
= _get_slot_val(page
, slot
);
1057 if (v
!= ASL_MSG_SLOT_FREE
)
1059 if ((v
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1061 i
= v
& ASL_MSG_OFFSET_MASK
;
1062 memcpy(&extval
, page
->data
+ i
, sizeof(char *));
1063 extvallen
= sizeof(char *);
1067 intval
= page
->data
+ v
;
1068 intvallen
= strlen(intval
) + 1;
1072 /* replace val and op for existing entry */
1074 /* easy case - remove val */
1079 page
->mem_size
-= (strlen(extval
) + 1);
1083 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
);
1084 if (op
!= IndexNull
) _set_slot_op(page
, slot
, o
);
1088 /* trivial case - internal val doesn't change */
1089 if ((intval
!= NULL
) && (streq(val
, intval
)))
1091 if (op
!= IndexNull
) _set_slot_op(page
, slot
, o
);
1095 /* trivial case - external val doesn't change */
1096 if ((extval
!= NULL
) && (streq(val
, extval
)))
1098 if (op
!= IndexNull
) _set_slot_op(page
, slot
, o
);
1103 * special case: we generally don't compress out holes in the data
1104 * space, but if this is the last string in the currently used data space
1105 * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots])
1107 i
= v
& ASL_MSG_OFFSET_MASK
;
1108 if ((intval
!= NULL
) && ((i
+ intvallen
) == page
->data_size
))
1110 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
);
1111 page
->data_size
-= intvallen
;
1115 else if ((extval
!= NULL
) && ((i
+ extvallen
) == page
->data_size
))
1117 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
);
1118 page
->data_size
-= extvallen
;
1119 page
->mem_size
-= (strlen(extval
) + 1);
1125 /* val changes - see if it needs to be external */
1126 newvallen
= strlen(val
) + 1;
1129 if (newvallen
> ASL_MSG_PAGE_DATA_SIZE
)
1132 newvallen
= sizeof(char *);
1135 /* check if there is room to change val in place */
1136 if (((extval
!= NULL
) && (newvallen
<= extvallen
)) || ((extval
== NULL
) && (newvallen
<= intvallen
)))
1140 page
->mem_size
-= (strlen(extval
) + 1);
1146 /* we can re-use the space of the old value */
1147 i
= v
& ASL_MSG_OFFSET_MASK
;
1149 if (newexternal
== 1)
1151 /* create an external val and copy in the new pointer */
1152 newval
= strdup(val
);
1153 if (newval
== NULL
) return -1;
1155 page
->mem_size
+= (strlen(newval
) + 1);
1156 _set_slot_val(page
, slot
, i
| ASL_MSG_KV_EXTERN
);
1157 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
1161 /* new internal value */
1162 _set_slot_val(page
, slot
, i
);
1163 memcpy(page
->data
+ i
, val
, newvallen
);
1166 if (op
!= IndexNull
) _set_slot_op(page
, slot
, o
);
1170 /* we're done with the old value if it is external - free it now */
1173 page
->mem_size
-= (strlen(extval
) + 1);
1179 if (newvallen
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
1181 /* can't re-use the old space, but there's room on the page */
1182 i
= page
->data_size
;
1183 page
->data_size
+= newvallen
;
1185 if (newexternal
== 1)
1187 /* create an external val and copy in the new pointer */
1188 newval
= strdup(val
);
1189 if (newval
== NULL
) return -1;
1191 page
->mem_size
+= (strlen(newval
) + 1);
1192 _set_slot_val(page
, slot
, i
| ASL_MSG_KV_EXTERN
);
1193 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
1197 /* new internal value */
1198 _set_slot_val(page
, slot
, i
);
1199 memcpy(page
->data
+ i
, val
, newvallen
);
1202 if (op
!= IndexNull
) _set_slot_op(page
, slot
, o
);
1207 /* no room on this page - free up existing entry and treat this as a new entry */
1208 if ((k
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1210 memcpy(&extval
, page
->data
+ (k
& ASL_MSG_OFFSET_MASK
), sizeof(char *));
1211 page
->mem_size
-= (strlen(extval
) + 1);
1215 _set_slot_key(page
, slot
, ASL_MSG_SLOT_FREE
);
1216 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
);
1217 _set_slot_op(page
, slot
, 0);
1219 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
1223 asl_msg_set_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
1225 char *special
, buf
[512];
1229 if (msg
== NULL
) return -1;
1230 if (key
== NULL
) return -1;
1232 /* Special case handling */
1235 /* if query modifier is set but op is zero, default to equality test */
1236 if ((op
!= 0) && ((op
& ASL_QUERY_OP_TRUE
) == 0)) op
|= ASL_QUERY_OP_EQUAL
;
1238 /* convert "Level" values to "0" through "7" */
1239 if (streq(key
, ASL_KEY_LEVEL
))
1241 if (val
== NULL
) val
= "7";
1242 else if ((val
[0] >= '0') && (val
[0] <= '7') && (val
[1] == '\0')) /* do nothing */;
1243 else if (strcaseeq(val
, ASL_STRING_EMERG
)) val
= "0";
1244 else if (strcaseeq(val
, ASL_STRING_ALERT
)) val
= "1";
1245 else if (strcaseeq(val
, ASL_STRING_CRIT
)) val
= "2";
1246 else if (strcaseeq(val
, ASL_STRING_ERR
)) val
= "3";
1247 else if (strcaseeq(val
, ASL_STRING_WARNING
)) val
= "4";
1248 else if (strcaseeq(val
, ASL_STRING_NOTICE
)) val
= "5";
1249 else if (strcaseeq(val
, ASL_STRING_INFO
)) val
= "6";
1250 else if (strcaseeq(val
, ASL_STRING_DEBUG
)) val
= "7";
1254 /* strip trailing newlines from "Message" values */
1255 if ((streq(key
, ASL_KEY_MSG
)) && (val
!= NULL
))
1259 while ((i
> 0) && (val
[i
- 1] == '\n')) i
--;
1260 if (i
== 0) val
= NULL
;
1263 /* use buf if it is big enough, else malloc a temporary buffer */
1264 if (i
< sizeof(buf
))
1266 memcpy(buf
, val
, i
);
1268 val
= (const char *)buf
;
1272 special
= malloc(i
+ 1);
1273 if (special
== NULL
) return -1;
1274 memcpy(special
, val
, i
);
1276 val
= (const char *)special
;
1281 status
= _asl_msg_set_kvo(msg
, key
, val
, op
);
1283 if (special
!= NULL
) free(special
);
1288 asl_msg_set_key_val(asl_msg_t
*msg
, const char *key
, const char *val
)
1290 return asl_msg_set_key_val_op(msg
, key
, val
, 0);
1294 _asl_msg_unset_page_slot(asl_msg_t
*page
, uint32_t slot
)
1299 if (page
== NULL
) return;
1301 if (slot
>= _slot_count(page
)) return;
1303 k
= _get_slot_key(page
, slot
);
1304 v
= _get_slot_val(page
, slot
);
1306 if (k
== ASL_MSG_SLOT_FREE
) return;
1308 if ((k
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1310 memcpy(&ext
, page
->data
+ (k
& ASL_MSG_OFFSET_MASK
), sizeof(char *));
1311 page
->mem_size
-= (strlen(ext
) + 1);
1315 if ((v
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1317 memcpy(&ext
, page
->data
+ (v
& ASL_MSG_OFFSET_MASK
), sizeof(char *));
1318 page
->mem_size
-= (strlen(ext
) + 1);
1322 _set_slot_key(page
, slot
, ASL_MSG_SLOT_FREE
);
1323 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
);
1324 _set_slot_op(page
, slot
, 0);
1331 * Frees external key and val strings, but does not try to reclaim data space.
1334 asl_msg_unset(asl_msg_t
*msg
, const char *key
)
1339 if (msg
== NULL
) return;
1340 if (key
== NULL
) return;
1345 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
1346 if (i
== IndexNull
) return;
1348 _asl_msg_unset_page_slot(page
, slot
);
1352 asl_msg_unset_index(asl_msg_t
*msg
, uint32_t n
)
1354 uint32_t slot
= IndexNull
;
1355 asl_msg_t
*page
= NULL
;
1357 if (msg
== NULL
) return;
1359 if (0 != _asl_msg_resolve_index(msg
, n
, &page
, &slot
)) return;
1360 _asl_msg_unset_page_slot(page
, slot
);
1364 #pragma mark copy and merge
1367 * Merge a key / val into a message (only ASL_TYPE_MSG).
1368 * Adds the key / val if the key is not found.
1369 * Does not replace the value if the key is found.
1372 _asl_msg_merge_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint16_t op
)
1377 if (msg
== NULL
) return;
1378 if (key
== NULL
) return;
1383 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
1384 if (i
!= IndexNull
) return;
1386 asl_msg_set_key_val_op(msg
, key
, val
, op
);
1390 * Merge msg into target (does not replace existing keys).
1391 * Creates a new asl_msg_t if target is NULL.
1395 asl_msg_merge(asl_msg_t
*target
, asl_msg_t
*msg
)
1397 uint32_t x
, type
, isnew
= 0;
1399 const char *key
, *val
;
1401 if (msg
== NULL
) return target
;
1403 type
= asl_get_type((asl_object_t
)msg
);
1408 target
= asl_msg_new(type
);
1411 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
1413 if (type
== ASL_TYPE_MSG
) op
= 0;
1414 if (isnew
== 1) asl_msg_set_key_val_op(target
, key
, val
, op
);
1415 else _asl_msg_merge_key_val_op(target
, key
, val
, op
);
1422 * replace key/value pairs from msg in target
1423 * Creates a new asl_msg_t if target is NULL.
1427 asl_msg_replace(asl_msg_t
*target
, asl_msg_t
*msg
)
1431 const char *key
, *val
;
1433 if (msg
== NULL
) return target
;
1435 type
= asl_get_type((asl_object_t
)msg
);
1437 if (target
== NULL
) target
= asl_msg_new(type
);
1439 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
1441 if (type
== ASL_TYPE_MSG
) op
= 0;
1442 asl_msg_set_key_val_op(target
, key
, val
, op
);
1453 asl_msg_copy(asl_msg_t
*msg
)
1455 return asl_msg_merge(NULL
, msg
);
1459 #pragma mark compare and test
1465 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1469 const char *key
, *va
, *vb
;
1471 if (asl_msg_count(a
) != asl_msg_count(b
)) return 0;
1477 for (x
= asl_msg_fetch(a
, 0, &key
, &va
, &oa
); x
!= IndexNull
; x
= asl_msg_fetch(a
, x
, &key
, &va
, &oa
))
1479 if (asl_msg_lookup(b
, key
, &vb
, &ob
) != 0) return 0;
1480 if (strcmp(va
, vb
)) return 0;
1481 if ((a
->asl_type
== ASL_TYPE_QUERY
) && (oa
!= ob
)) return 0;
1488 _asl_isanumber(const char *s
)
1492 if (s
== NULL
) return 0;
1495 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1497 if (s
[i
] == '\0') return 0;
1499 for (; s
[i
] != '\0'; i
++)
1501 if (!isdigit(s
[i
])) return 0;
1508 _asl_msg_basic_test(uint32_t op
, const char *q
, const char *m
, uint32_t n
)
1516 t
= op
& ASL_QUERY_OP_TRUE
;
1518 /* NULL value from query or message string fails */
1519 if ((q
== NULL
) || (m
== NULL
)) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1521 if (op
& ASL_QUERY_OP_REGEX
)
1523 /* greater than or less than make no sense in substring search */
1524 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1526 memset(&rex
, 0, sizeof(regex_t
));
1528 rflags
= REG_EXTENDED
| REG_NOSUB
;
1529 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1531 /* A bad reqular expression matches nothing */
1532 if (regcomp(&rex
, q
, rflags
) != 0) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1534 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1537 if (t
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp
!= 0);
1541 if (op
& ASL_QUERY_OP_NUMERIC
)
1543 if (_asl_isanumber(q
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1544 if (_asl_isanumber(m
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1551 case ASL_QUERY_OP_EQUAL
: return (nm
== nq
);
1552 case ASL_QUERY_OP_GREATER
: return (nm
> nq
);
1553 case ASL_QUERY_OP_GREATER_EQUAL
: return (nm
>= nq
);
1554 case ASL_QUERY_OP_LESS
: return (nm
< nq
);
1555 case ASL_QUERY_OP_LESS_EQUAL
: return (nm
<= nq
);
1556 case ASL_QUERY_OP_NOT_EQUAL
: return (nm
!= nq
);
1557 default: return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1562 if (op
& ASL_QUERY_OP_CASEFOLD
)
1564 if (n
== 0) cmp
= strcasecmp(m
, q
);
1565 else cmp
= strncasecmp(m
, q
, n
);
1569 if (n
== 0) cmp
= strcmp(m
, q
);
1570 else cmp
= strncmp(m
, q
, n
);
1575 case ASL_QUERY_OP_EQUAL
: return (cmp
== 0);
1576 case ASL_QUERY_OP_GREATER
: return (cmp
> 0);
1577 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp
>= 0);
1578 case ASL_QUERY_OP_LESS
: return (cmp
< 0);
1579 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp
<= 0);
1580 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp
!= 0);
1583 return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1587 _asl_msg_test_substring(uint32_t op
, const char *q
, const char *m
)
1589 uint32_t t
, i
, d
, lm
, lq
, match
, newop
;
1591 t
= op
& ASL_QUERY_OP_TRUE
;
1594 if (m
!= NULL
) lm
= strlen(m
);
1597 if (q
!= NULL
) lq
= strlen(q
);
1599 /* NULL is a substring of any string */
1600 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1602 /* A long string is defined to be not equal to a short string */
1603 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1605 /* greater than or less than make no sense in substring search */
1606 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1609 * We scan the string doing an equality test.
1610 * If the input test is equality, we stop as soon as we hit a match.
1611 * Otherwise we keep scanning the whole message string.
1614 newop
|= ASL_QUERY_OP_EQUAL
;
1618 for (i
= 0; i
<= d
; i
++)
1620 if (_asl_msg_basic_test(newop
, q
, m
+ i
, lq
) != 0)
1622 if (t
& ASL_QUERY_OP_EQUAL
) return 1;
1627 /* If the input test was for equality, no matches were found */
1628 if (t
& ASL_QUERY_OP_EQUAL
) return 0;
1630 /* The input test was for not equal. Return true if no matches were found */
1631 return (match
== 0);
1635 _asl_msg_test_prefix(uint32_t op
, const char *q
, const char *m
)
1639 t
= op
& ASL_QUERY_OP_TRUE
;
1642 if (m
!= NULL
) lm
= strlen(m
);
1645 if (q
!= NULL
) lq
= strlen(q
);
1647 /* NULL is a prefix of any string */
1648 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1650 /* A long string is defined to be not equal to a short string */
1651 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1653 /* Compare two equal-length strings */
1654 return _asl_msg_basic_test(op
, q
, m
, lq
);
1658 _asl_msg_test_suffix(uint32_t op
, const char *q
, const char *m
)
1660 uint32_t lm
, lq
, d
, t
;
1662 t
= op
& ASL_QUERY_OP_TRUE
;
1665 if (m
!= NULL
) lm
= strlen(m
);
1668 if (q
!= NULL
) lq
= strlen(q
);
1670 /* NULL is a suffix of any string */
1671 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1673 /* A long string is defined to be not equal to a short string */
1674 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1676 /* Compare two equal-length strings */
1678 return _asl_msg_basic_test(op
, q
, m
+ d
, lq
);
1682 * Splits out prefix, suffix, and substring tests.
1683 * Sends the rest to _asl_msg_basic_test().
1686 _asl_msg_test_expression(uint32_t op
, const char *q
, const char *m
)
1690 t
= op
& ASL_QUERY_OP_TRUE
;
1691 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1693 if (op
& ASL_QUERY_OP_PREFIX
)
1695 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
);
1696 return _asl_msg_test_prefix(op
, q
, m
);
1698 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
);
1700 return _asl_msg_basic_test(op
, q
, m
, 0);
1704 * Special case for comparing time values.
1705 * If both inputs are time strings, this compares the time
1706 * value in seconds. Otherwise it just does normal matching.
1709 _asl_msg_test_time_expression(uint32_t op
, const char *q
, const char *m
)
1714 if ((op
& ASL_QUERY_OP_PREFIX
) || (op
& ASL_QUERY_OP_SUFFIX
) || (op
& ASL_QUERY_OP_REGEX
)) return _asl_msg_test_expression(op
, q
, m
);
1715 if ((q
== NULL
) || (m
== NULL
)) return _asl_msg_test_expression(op
, q
, m
);
1717 tq
= asl_core_parse_time(q
, NULL
);
1718 if (tq
< 0) return _asl_msg_test_expression(op
, q
, m
);
1720 tm
= asl_core_parse_time(m
, NULL
);
1721 if (tm
< 0) return _asl_msg_test_expression(op
, q
, m
);
1723 t
= op
& ASL_QUERY_OP_TRUE
;
1727 case ASL_QUERY_OP_FALSE
:
1731 case ASL_QUERY_OP_EQUAL
:
1733 if (tm
== tq
) return 1;
1736 case ASL_QUERY_OP_GREATER
:
1738 if (tm
> tq
) return 1;
1741 case ASL_QUERY_OP_GREATER_EQUAL
:
1743 if (tm
>= tq
) return 1;
1746 case ASL_QUERY_OP_LESS
:
1748 if (tm
< tq
) return 1;
1751 case ASL_QUERY_OP_LESS_EQUAL
:
1753 if (tm
<= tq
) return 1;
1756 case ASL_QUERY_OP_NOT_EQUAL
:
1758 if (tm
!= tq
) return 1;
1761 case ASL_QUERY_OP_TRUE
:
1771 /* test a query against a message */
1772 __private_extern__
int
1773 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
1778 const char *kq
, *vq
, *vm
;
1781 * Check each simple expression (key op val) separately.
1782 * The query suceeds (returns 1) if all simple expressions
1783 * succeed (i.e. AND the simple expressions).
1790 for (x
= asl_msg_fetch(q
, 0, &kq
, &vq
, &op
); x
!= IndexNull
; x
= asl_msg_fetch(q
, x
, &kq
, &vq
, &op
))
1792 /* Find query key in the message */
1794 i
= asl_msg_lookup(m
, kq
, &vm
, NULL
);
1796 /* ASL_QUERY_OP_TRUE tests if key is present in the message */
1797 t
= op
& ASL_QUERY_OP_TRUE
;
1798 if (t
== ASL_QUERY_OP_TRUE
)
1800 if (i
!= 0) return 0;
1804 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1805 if (t
== ASL_QUERY_OP_FALSE
)
1807 if (i
== 0) return 0;
1813 /* the message does NOT have query key - fail unless we are testing not equal */
1814 if (t
== ASL_QUERY_OP_NOT_EQUAL
) continue;
1819 if (streq(kq
, ASL_KEY_TIME
))
1821 cmp
= _asl_msg_test_time_expression(op
, vq
, vm
);
1825 cmp
= _asl_msg_test_expression(op
, vq
, vm
);
1828 if (cmp
== 0) return 0;
1834 /* returns 1 if a and b match, 0 otherwise */
1836 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1839 if (a
== NULL
) return 0;
1840 if (b
== NULL
) return 0;
1842 if (a
->asl_type
== b
->asl_type
) return _asl_msg_equal(a
, b
);
1843 if (a
->asl_type
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
);
1844 return _asl_msg_test(b
, a
);
1848 * Test a message against a query list.
1849 * Returns 1 if msg matches any query in the list, 0 otherwise.
1850 * Returns 1 if the query list is NULL or empty.
1853 asl_msg_cmp_list(asl_msg_t
*msg
, asl_msg_list_t
*list
)
1857 if (msg
== NULL
) return 0;
1858 if (list
== NULL
) return 1;
1859 if (list
->count
== 0) return 1;
1861 for (i
= 0; i
< list
->count
; i
++)
1863 if (_asl_msg_test(list
->msg
[i
], msg
)) return 1;
1870 #pragma mark string representation
1873 _asl_time_string(const char *infmt
, const char *str
, const char *nano
)
1877 char *ltime
, *out
, *p
, *q
;
1878 char ltbuf
[32], nanobuf
[16], fmt
[32], zstr
[8];
1880 uint32_t subsec
= 0;
1884 memset(zstr
, 0, sizeof(zstr
));
1891 * The longest infmt string we understand is "-hh:mm.N" (8 chars), so
1892 * it is safe to ignore the input if it doesn't fit in the temp buffer.
1893 * The default is local time zone format.
1897 snprintf(fmt
, sizeof(fmt
), "local");
1899 else if (strlen(infmt
) >= sizeof (fmt
))
1901 snprintf(fmt
, sizeof(fmt
), "local");
1905 snprintf(fmt
, sizeof(fmt
), "%s", infmt
);
1908 q
= strchr(fmt
, '.');
1913 if (q
!= '\0') subsec
= atoi(q
);
1922 if (nano
!= NULL
) nsec
= atoi(nano
);
1923 snprintf(nanobuf
, sizeof(nanobuf
), ".%09u", nsec
);
1924 if (subsec
> 9) subsec
= 9;
1925 nanobuf
[subsec
+ 1] = '\0';
1929 if (str
!= NULL
) tick
= asl_core_parse_time(str
, NULL
);
1931 if ((!strcasecmp(fmt
, "lcl")) || (!strcasecmp(fmt
, "local")))
1933 ltime
= ctime_r(&tick
, ltbuf
);
1934 if (ltime
== NULL
) return NULL
;
1936 asprintf(&out
, "%s%s", ltime
+ 4, nanobuf
);
1940 if ((!strcasecmp(fmt
, "jz")) || (!strcasecmp(fmt
, "iso8601")) || (!strcasecmp(fmt
, "iso8601e")))
1943 if (!strncasecmp(fmt
, "iso8601", 7)) sep
= 'T';
1945 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1947 off
= stm
.tm_gmtoff
;
1948 if ((neg
= (off
< 0))) off
*= -1;
1953 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg
? '-' : '+', (long long) zh
);
1954 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg
? '-' : '+', (long long) zh
, (long long) zm
);
1956 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
);
1960 if (!strcasecmp(fmt
, "iso8601b"))
1962 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1964 off
= stm
.tm_gmtoff
;
1965 if ((neg
= (off
< 0))) off
*= -1;
1970 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg
? '-' : '+', (long long) zh
);
1971 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg
? '-' : '+', (long long) zh
, (long long) zm
);
1973 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
);
1977 if ((!strcasecmp(fmt
, "sec")) || (!strcasecmp(fmt
, "raw")))
1979 asprintf(&out
, "%llu%s", (unsigned long long) tick
, nanobuf
);
1983 if (!strcasecmp(fmt
, "j"))
1985 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1986 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
);
1990 if ((!strcasecmp(fmt
, "utc")) || (!strcasecmp(fmt
, "zulu")) || (!strcasecmp(fmt
, "iso8601z")) || (!strcasecmp(fmt
, "iso8601ez")))
1993 if (!strncasecmp(fmt
, "iso8601", 7)) sep
= 'T';
1995 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1996 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
);
2000 if (!strcasecmp(fmt
, "iso8601bz"))
2002 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
2003 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
);
2007 if ((fmt
[1] == '\0') && (((fmt
[0] >= 'a') && (fmt
[0] <= 'z')) || ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))))
2010 if (z
>= 'a') z
-= 32;
2012 if (z
== 'Z') off
= 0;
2013 else if ((z
>= 'A') && (z
<= 'I')) off
= ((z
- 'A') + 1) * SEC_PER_HOUR
;
2014 else if ((z
>= 'K') && (z
<= 'M')) off
= (z
- 'A') * SEC_PER_HOUR
;
2015 else if ((z
>= 'N') && (z
<= 'Y')) off
= ('M' - z
) * SEC_PER_HOUR
;
2020 if (fmt
[0] == '-') neg
= true;
2021 if ((*p
== '-') || (*p
== '+')) p
++;
2022 if ((*p
) >= '0' && (*p
<= '9'))
2027 if (p
!= NULL
) zm
= atoi(p
+ 1);
2034 off
= (zh
* 3600) + (zm
* 60);
2037 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg
? '-' : '+', (long long) zh
);
2038 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg
? '-' : '+', (long long) zh
, (long long) zm
);
2044 memset(&stm
, 0, sizeof (struct tm
));
2045 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
2047 if ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))
2049 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]);
2051 else if ((fmt
[0] >= 'a') && (fmt
[0] <= 'z'))
2053 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);
2057 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
);
2064 /* called from asl_format_message and _asl_send_message */
2065 __private_extern__ asl_string_t
*
2066 asl_msg_to_string_raw(uint32_t encoding
, asl_msg_t
*msg
, const char *tfmt
)
2068 uint32_t i
, x
, count
;
2069 const char *key
, *val
, *nano
;
2072 if (msg
== NULL
) return NULL
;
2074 count
= asl_msg_count(msg
);
2075 if (count
== 0) return NULL
;
2077 str
= asl_string_new(encoding
);
2078 if (str
== NULL
) return NULL
;
2085 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
2087 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
2089 if (key
== NULL
) continue;
2091 if (i
> 0) asl_string_append_char_no_encoding(str
, ' ');
2093 asl_string_append_char_no_encoding(str
, '[');
2094 asl_string_append_asl_key(str
, key
);
2096 if (!strcmp(key
, ASL_KEY_TIME
))
2099 asl_string_append_char_no_encoding(str
, ' ');
2101 if (val
!= NULL
) vtime
= _asl_time_string(tfmt
, val
, nano
);
2105 asl_string_append_no_encoding(str
, vtime
);
2110 asl_string_append_char_no_encoding(str
, '0');
2113 else if (val
!= NULL
)
2115 asl_string_append_char_no_encoding(str
, ' ');
2116 asl_string_append(str
, val
);
2119 asl_string_append_char_no_encoding(str
, ']');
2128 asl_string_append_asl_msg(asl_string_t
*str
, asl_msg_t
*msg
)
2130 const char *key
, *val
;
2134 if (msg
== NULL
) return str
;
2136 if (msg
->asl_type
== ASL_TYPE_QUERY
) asl_string_append(str
, "Q ");
2139 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
2141 if (i
!= 0) asl_string_append_char_no_encoding(str
, ' ');
2144 asl_string_append_char_no_encoding(str
, '[');
2146 if (msg
->asl_type
== ASL_TYPE_QUERY
)
2148 asl_string_append_op(str
, op
);
2149 asl_string_append_char_no_encoding(str
, ' ');
2152 asl_string_append_asl_key(str
, key
);
2156 asl_string_append_char_no_encoding(str
, ' ');
2157 asl_string_append(str
, val
);
2160 asl_string_append_char_no_encoding(str
, ']');
2167 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
2170 asl_string_t
*str
= asl_string_new(ASL_ENCODE_ASL
);
2171 if (str
== NULL
) return NULL
;
2173 str
= asl_string_append_asl_msg(str
, msg
);
2174 *len
= asl_string_length(str
);
2175 out
= asl_string_release_return_bytes(str
);
2180 _asl_msg_op_from_string(char *o
)
2184 op
= ASL_QUERY_OP_NULL
;
2186 if (o
== NULL
) return op
;
2188 for (i
= 0; o
[i
] != '\0'; i
++)
2190 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
2191 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
2192 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
2193 if (o
[i
] == 'N') op
|= ASL_QUERY_OP_NUMERIC
;
2194 if (o
[i
] == 'S') op
|= ASL_QUERY_OP_SUBSTRING
;
2195 if (o
[i
] == 'A') op
|= ASL_QUERY_OP_PREFIX
;
2196 if (o
[i
] == 'Z') op
|= ASL_QUERY_OP_SUFFIX
;
2197 if (o
[i
] == '<') op
|= ASL_QUERY_OP_LESS
;
2198 if (o
[i
] == '>') op
|= ASL_QUERY_OP_GREATER
;
2199 if (o
[i
] == '=') op
|= ASL_QUERY_OP_EQUAL
;
2200 if (o
[i
] == '!') op
|= ASL_QUERY_OP_NOT_EQUAL
;
2201 if (o
[i
] == 'T') op
|= ASL_QUERY_OP_TRUE
;
2208 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
2210 char *str
, *out
, c
, oval
;
2211 uint32_t i
, len
, n
, outlen
;
2215 if (p
== NULL
) return NULL
;
2216 if (*p
== NULL
) return NULL
;
2217 if (**p
== '\0') return NULL
;
2219 /* skip one space if it's there (word separator) */
2220 if (**p
== ' ') (*p
)++;
2222 /* skip leading white space */
2225 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
2228 if (**p
== '\0') return NULL
;
2229 if (**p
== '\n') return NULL
;
2240 if (out
== NULL
) return NULL
;
2247 /* scan for token and calulate it's length (input and decoded output len) */
2255 /* stop scanning when we hit a delimiter */
2256 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
2262 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
2267 if (str
[++len
] == '\0') return NULL
;
2271 if (str
[++len
] == '\0') return NULL
;
2272 if (str
[++len
] == '\0') return NULL
;
2274 else if ((c
>= '0') && (c
<= '3'))
2276 if (str
[++len
] == '\0') return NULL
;
2277 if (str
[++len
] == '\0') return NULL
;
2291 if ((len
== 0) && (**p
== ']'))
2296 if (out
== NULL
) return NULL
;
2305 out
= malloc(outlen
+ 1);
2306 if (out
== NULL
) return NULL
;
2309 for (i
= 0; i
< len
; i
++)
2366 if (str
[i
] == '?') out
[n
++] = 127;
2367 else out
[n
++] = str
[i
] - 64;
2376 if (str
[i
] == '?') out
[n
++] = 255;
2377 else out
[n
++] = str
[i
] + 64;
2382 out
[n
++] = str
[i
] + 128;
2392 else if ((c
>= '0') && (c
<= '3'))
2394 oval
= (c
- '0') * 64;
2398 if ((c
< '0') || (c
> '7'))
2405 oval
+= ((c
- '0') * 8);
2409 if ((c
< '0') || (c
> '7'))
2430 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
2441 asl_msg_from_string(const char *buf
)
2443 uint32_t tt
, type
, op
;
2444 char *k
, *v
, *o
, *p
;
2447 if (buf
== NULL
) return NULL
;
2449 type
= ASL_TYPE_MSG
;
2452 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2453 if (k
== NULL
) return NULL
;
2457 type
= ASL_TYPE_QUERY
;
2460 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2462 else if (tt
== TOKEN_INT
)
2464 /* Leading integer is a string length - skip it */
2466 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2467 if (k
== NULL
) return NULL
;
2470 out
= asl_msg_new(ASL_TYPE_MSG
);
2471 if (out
== NULL
) return NULL
;
2473 out
->asl_type
= type
;
2475 /* OPEN WORD [WORD [WORD]] CLOSE */
2478 op
= ASL_QUERY_OP_NULL
;
2480 if (tt
!= TOKEN_OPEN
)
2482 asl_msg_release(out
);
2488 /* get op for query type */
2489 if (type
== ASL_TYPE_QUERY
)
2491 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
2492 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
2494 if (o
!= NULL
) free(o
);
2495 asl_msg_release(out
);
2499 op
= _asl_msg_op_from_string(o
);
2503 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2504 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
2505 if ((k
== NULL
) || (tt
!= TOKEN_WORD
))
2507 if (k
!= NULL
) free(k
);
2508 asl_msg_release(out
);
2512 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
2513 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
2516 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
2521 if (tt
== TOKEN_CLOSE
)
2523 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
2525 else if (tt
== TOKEN_WORD
)
2527 asl_msg_set_key_val_op(out
, k
, v
, op
);
2531 if (k
!= NULL
) free(k
);
2532 if (v
!= NULL
) free(v
);
2533 asl_msg_release(out
);
2537 if (k
!= NULL
) free(k
);
2538 if (v
!= NULL
) free(v
);
2540 if (tt
!= TOKEN_CLOSE
)
2542 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2543 if (k
== NULL
) break;
2545 if (tt
!= TOKEN_CLOSE
)
2547 asl_msg_release(out
);
2554 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2555 if (k
== NULL
) break;
2562 _asl_level_string(int level
)
2564 if (level
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
;
2565 if (level
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
;
2566 if (level
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
;
2567 if (level
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
;
2568 if (level
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
;
2569 if (level
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
;
2570 if (level
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
;
2571 if (level
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
;
2576 _asl_level_char(int level
)
2578 if (level
== ASL_LEVEL_EMERG
) return "P";
2579 if (level
== ASL_LEVEL_ALERT
) return "A";
2580 if (level
== ASL_LEVEL_CRIT
) return "C";
2581 if (level
== ASL_LEVEL_ERR
) return "E";
2582 if (level
== ASL_LEVEL_WARNING
) return "W";
2583 if (level
== ASL_LEVEL_NOTICE
) return "N";
2584 if (level
== ASL_LEVEL_INFO
) return "I";
2585 if (level
== ASL_LEVEL_DEBUG
) return "D";
2590 * Find the value for a key in a message and append a formatted value to str.
2591 * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)).
2592 * WARNING: modifies kf!
2594 static asl_string_t
*
2595 _asl_string_append_value_for_key_format(asl_string_t
*str
, asl_msg_t
*msg
, char *kf
, const char *tfmt
)
2597 uint32_t i
, get_fmt
;
2600 const char *mval
, *nano
;
2602 if (str
== NULL
) return NULL
;
2603 if (msg
== NULL
) return str
;
2604 if (kf
== NULL
) return str
;
2610 for (i
= 0; kf
[i
] != '\0'; i
++)
2617 else if (kf
[i
] != '(')
2619 if (key
== NULL
) key
= kf
+ i
;
2620 else if ((get_fmt
== 1) && (fmt
== NULL
)) fmt
= kf
+ i
;
2624 if (key
== NULL
) return str
;
2627 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
2629 status
= asl_msg_lookup(msg
, key
, &mval
, NULL
);
2630 if ((status
!= 0) || (mval
== NULL
)) return str
;
2632 if (!strcmp(key
, ASL_KEY_TIME
))
2636 /* format in $((Time)(fmt)) overrides tfmt */
2639 fval
= _asl_time_string(tfmt
, mval
, nano
);
2643 fval
= _asl_time_string(fmt
, mval
, nano
);
2648 asl_string_append_no_encoding(str
, fval
);
2653 asl_string_append_char_no_encoding(str
, '0');
2659 /* Level: num str */
2660 if (!strcmp(key
, ASL_KEY_LEVEL
))
2664 asl_string_append_no_encoding(str
, mval
);
2666 else if (!strcmp(fmt
, "str"))
2668 mval
= _asl_level_string(atoi(mval
));
2669 asl_string_append_no_encoding(str
, mval
);
2671 else if (!strcmp(fmt
, "char"))
2673 mval
= _asl_level_char(atoi(mval
));
2674 asl_string_append_no_encoding(str
, mval
);
2678 asl_string_append_no_encoding(str
, mval
);
2684 return asl_string_append(str
, mval
);
2688 * format a message for printing
2689 * out parameter len returns string length including trailing NUL
2692 asl_format_message(asl_msg_t
*msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
2694 char *out
, *vtime
, *k
, c
, skey
[512], tfmt_ext
[16];
2695 const char *vhost
, *vpid
, *vsender
, *vmessage
, *vlevel
, *vrefproc
, *vrefpid
, *v
, *key
, *val
, *nano
;
2696 int i
, j
, l
, mf
, paren
, oval
, level
;
2704 if (msg
== NULL
) return NULL
;
2708 if (mfmt
== NULL
) mf
= MFMT_RAW
;
2709 else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf
= MFMT_RAW
;
2710 else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf
= MFMT_STD
;
2711 else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf
= MFMT_BSD
;
2712 else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf
= MFMT_XML
;
2713 else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf
= MFMT_MSG
;
2714 else if ((!strncmp(mfmt
, ASL_MSG_FMT_RAW
, 3)) && (mfmt
[3] == '.'))
2717 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2719 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "sec.%s", mfmt
+ 4);
2720 tfmt
= (const char *)tfmt_ext
;
2723 else if ((!strncmp(mfmt
, ASL_MSG_FMT_STD
, 3)) && (mfmt
[3] == '.'))
2726 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2728 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt
+ 4);
2729 tfmt
= (const char *)tfmt_ext
;
2732 else if ((!strncmp(mfmt
, ASL_MSG_FMT_BSD
, 3)) && (mfmt
[3] == '.'))
2735 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2737 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt
+ 4);
2738 tfmt
= (const char *)tfmt_ext
;
2744 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
2748 str
= asl_msg_to_string_raw(text_encoding
, msg
, tfmt
);
2749 asl_string_append_char_no_encoding(str
, '\n');
2751 *len
= asl_string_length(str
);
2752 out
= asl_string_release_return_bytes(str
);
2760 if (asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
) != 0) return NULL
;
2762 str
= asl_string_new(text_encoding
);
2763 if (str
== NULL
) return NULL
;
2765 asl_string_append(str
, vmessage
);
2766 asl_string_append_char_no_encoding(str
, '\n');
2768 *len
= asl_string_length(str
);
2769 out
= asl_string_release_return_bytes(str
);
2773 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
2775 /* COMMON: Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/
2776 /* BSD: <COMMON>: message */
2777 /* STD: <COMMON> <Level>: message */
2789 if (asl_msg_lookup(msg
, ASL_KEY_TIME
, &v
, NULL
) == 0)
2791 vtime
= _asl_time_string(tfmt
, v
, nano
);
2795 if (asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &vlevel
, NULL
) == 0)
2797 if (vlevel
!= NULL
) level
= atoi(vlevel
);
2800 if (asl_msg_lookup(msg
, ASL_KEY_HOST
, &vhost
, NULL
) == 0)
2802 if (vhost
== NULL
) vhost
= "unknown";
2805 if (asl_msg_lookup(msg
, ASL_KEY_SENDER
, &vsender
, NULL
) == 0)
2807 if (vsender
== NULL
) vsender
= "unknown";
2810 asl_msg_lookup(msg
, ASL_KEY_PID
, &vpid
, NULL
);
2811 asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
);
2812 asl_msg_lookup(msg
, ASL_KEY_REF_PROC
, &vrefproc
, NULL
);
2813 asl_msg_lookup(msg
, ASL_KEY_REF_PID
, &vrefpid
, NULL
);
2816 str
= asl_string_new(text_encoding
);
2817 if (str
== NULL
) return NULL
;
2821 asl_string_append(str
, vtime
);
2826 asl_string_append_char_no_encoding(str
, '0');
2829 asl_string_append_char_no_encoding(str
, ' ');
2830 asl_string_append(str
, vhost
);
2831 asl_string_append_char_no_encoding(str
, ' ');
2832 asl_string_append(str
, vsender
);
2834 if ((vpid
!= NULL
) && (strcmp(vpid
, "-1")))
2836 asl_string_append_char_no_encoding(str
, '[');
2837 asl_string_append(str
, vpid
);
2838 asl_string_append_char_no_encoding(str
, ']');
2841 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_no_encoding(str
, " (");
2843 if (vrefproc
!= NULL
) asl_string_append(str
, vrefproc
);
2844 if (vrefpid
!= NULL
)
2846 asl_string_append_char_no_encoding(str
, '[');
2847 asl_string_append(str
, vrefpid
);
2848 asl_string_append_char_no_encoding(str
, ']');
2851 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_char_no_encoding(str
, ')');
2855 asl_string_append_no_encoding(str
, " <");
2856 asl_string_append(str
, _asl_level_string(level
));
2857 asl_string_append_char_no_encoding(str
, '>');
2860 asl_string_append_no_encoding(str
, ": ");
2861 if (vmessage
!= NULL
) asl_string_append(str
, vmessage
);
2862 asl_string_append_char_no_encoding(str
, '\n');
2864 *len
= asl_string_length(str
);
2865 out
= asl_string_release_return_bytes(str
);
2871 str
= asl_string_new(text_encoding
);
2872 if (str
== NULL
) return NULL
;
2874 asl_string_append_char_no_encoding(str
, '\t');
2875 asl_string_append_no_encoding(str
, "<dict>");
2876 asl_string_append_char_no_encoding(str
, '\n');
2878 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
2880 if (asl_is_utf8(key
) == 1)
2882 asl_string_append_xml_tag(str
, "key", key
);
2883 if (!strcmp(key
, ASL_KEY_TIME
))
2885 vtime
= _asl_time_string(tfmt
, val
, nano
);
2888 asl_string_append_xml_tag(str
, "string", vtime
);
2893 asl_string_append_xml_tag(str
, "string", "0");
2898 if (asl_is_utf8(val
) == 1) asl_string_append_xml_tag(str
, "string", val
);
2901 b64
= asl_b64_encode((uint8_t *)val
, strlen(val
));
2902 asl_string_append_xml_tag(str
, "data", (char *)b64
);
2909 asl_string_append_char_no_encoding(str
, '\t');
2910 asl_string_append_no_encoding(str
, "</dict>");
2911 asl_string_append_char_no_encoding(str
, '\n');
2913 *len
= asl_string_length(str
);
2914 out
= asl_string_release_return_bytes(str
);
2920 * The format string may contain arbitrary characters.
2921 * Keys are identified by $Key or $(Key). The value for
2922 * that key is substituted. If there are alterate formats
2923 * for the value (for example a time may be formatted as
2924 * raw seconds, in UTC, or a local timezone), then the
2925 * key may be $((Key)(Format)). "\$" prints a plain "$".
2928 str
= asl_string_new(text_encoding
);
2929 if (str
== NULL
) return NULL
;
2932 * We need enough space to copy any keys found in mfmt.
2933 * The key obviously can't be longer than strlen(mfmt),
2934 * in fact, keys must be shorter, since there's at least a '$'
2935 * in front of the key, so we allocate a buffer with strlen(mfmt).
2936 * If strlen(mfmt) <= sizeof(skey), we use skey to avoid a malloc.
2940 if (x
<= sizeof(skey
))
2947 if (k
== NULL
) return NULL
;
2952 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2958 /* scan key, (key) or ((key)(format)) */
2959 for (j
= i
+ 1; mfmt
[j
] != 0; j
++)
2965 else if (mfmt
[j
] == ')')
2967 if (paren
> 0) paren
--;
2974 else if (((mfmt
[j
] == ' ') || (mfmt
[j
] == '\t')) && (paren
== 0)) break;
2977 /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */
2979 memcpy(k
, mfmt
+i
+1, l
);
2981 _asl_string_append_value_for_key_format(str
, msg
, k
, tfmt
);
2987 if (mfmt
[i
] == '\\')
2990 if (mfmt
[i
] == '$') asl_string_append_char_no_encoding(str
, '$');
2991 else if (mfmt
[i
] == 'e') asl_string_append_char_no_encoding(str
, '\e');
2992 else if (mfmt
[i
] == 's') asl_string_append_char_no_encoding(str
, ' ');
2993 else if (mfmt
[i
] == 'a') asl_string_append_char_no_encoding(str
, '\a');
2994 else if (mfmt
[i
] == 'b') asl_string_append_char_no_encoding(str
, '\b');
2995 else if (mfmt
[i
] == 'f') asl_string_append_char_no_encoding(str
, '\f');
2996 else if (mfmt
[i
] == 'n') asl_string_append_char_no_encoding(str
, '\n');
2997 else if (mfmt
[i
] == 'r') asl_string_append_char_no_encoding(str
, '\r');
2998 else if (mfmt
[i
] == 't') asl_string_append_char_no_encoding(str
, '\t');
2999 else if (mfmt
[i
] == 'v') asl_string_append_char_no_encoding(str
, '\v');
3000 else if (mfmt
[i
] == '\'') asl_string_append_char_no_encoding(str
, '\'');
3001 else if (mfmt
[i
] == '\\') asl_string_append_char_no_encoding(str
, '\\');
3002 else if (isdigit(mfmt
[i
]))
3004 oval
= mfmt
[i
] - '0';
3005 if (isdigit(mfmt
[i
+1]))
3008 oval
= (oval
* 8) + (mfmt
[i
] - '0');
3009 if (isdigit(mfmt
[i
+1]))
3012 oval
= (oval
* 8) + (mfmt
[i
] - '0');
3016 asl_string_append_char_no_encoding(str
, c
);
3021 if (mfmt
[i
] == '\0') break;
3022 asl_string_append_char_no_encoding(str
, mfmt
[i
]);
3025 if (k
!= skey
) free(k
);
3027 asl_string_append_char_no_encoding(str
, '\n');
3029 *len
= asl_string_length(str
);
3030 out
= asl_string_release_return_bytes(str
);
3035 #pragma mark xpc conversion
3038 _asl_msg_to_xpc(asl_msg_t
*msg
, xpc_object_t dict
)
3041 const char *key
, *val
, *nano
;
3044 if (msg
== NULL
) return;
3045 if (dict
== NULL
) return;
3048 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
3050 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
3052 if (key
== NULL
) continue;
3055 kx
= _asl_msg_std_key(key
, len
);
3059 xpc_object_t obj
= xpc_null_create();
3060 xpc_dictionary_set_value(dict
, key
, obj
);
3065 if (streq(key
, ASL_KEY_SENDER_MACH_UUID
))
3068 if (uuid_parse(val
, v
) == 0)
3070 xpc_object_t obj
= xpc_uuid_create(v
);
3071 xpc_dictionary_set_value(dict
, key
, obj
);
3077 xpc_object_t obj
= xpc_string_create(val
);
3078 xpc_dictionary_set_value(dict
, key
, obj
);
3082 else if (kx
== ASL_STD_KEY_TIME
)
3084 uint64_t t
= NSEC_PER_SEC
* asl_core_parse_time(val
, NULL
);
3085 if (nano
!= NULL
) t
+= atoll(nano
);
3086 xpc_object_t obj
= xpc_date_create(t
);
3087 xpc_dictionary_set_value(dict
, key
, obj
);
3090 else if (kx
== ASL_STD_KEY_NANO
)
3092 /* handled with ASL_STD_KEY_TIME */
3094 else if ((kx
== ASL_STD_KEY_PID
) || (kx
== ASL_STD_KEY_REF_PID
))
3096 int64_t v
= atoll(val
);
3097 xpc_object_t obj
= xpc_int64_create(v
);
3098 xpc_dictionary_set_value(dict
, key
, obj
);
3101 else if ((kx
== ASL_STD_KEY_UID
) || (kx
== ASL_STD_KEY_GID
))
3103 int64_t v
= atoll(val
);
3104 xpc_object_t obj
= xpc_int64_create(v
);
3105 xpc_dictionary_set_value(dict
, key
, obj
);
3108 else if (kx
== ASL_STD_KEY_LEVEL
)
3110 int64_t v
= atoll(val
);
3111 xpc_object_t obj
= xpc_int64_create(v
);
3112 xpc_dictionary_set_value(dict
, key
, obj
);
3115 else if ((kx
== ASL_STD_KEY_READ_UID
) || (kx
== ASL_STD_KEY_READ_GID
))
3117 int64_t v
= atoll(val
);
3118 xpc_object_t obj
= xpc_int64_create(v
);
3119 xpc_dictionary_set_value(dict
, key
, obj
);
3122 else if (kx
== ASL_STD_KEY_MSG_ID
)
3128 xpc_object_t obj
= xpc_string_create(val
);
3129 xpc_dictionary_set_value(dict
, key
, obj
);
3136 _asl_log_args_to_xpc(asl_object_t client
, asl_object_t msg
, xpc_object_t dict
)
3138 _asl_msg_to_xpc(asl_client_kvdict((asl_client_t
*)client
), dict
);
3139 _asl_msg_to_xpc((asl_msg_t
*)msg
, dict
);
3143 #pragma mark asl_object support
3145 static asl_object_private_t
*
3146 _jump_alloc(uint32_t type
)
3148 return (asl_object_private_t
*)asl_msg_new(type
);
3152 _jump_dealloc(asl_object_private_t
*obj
)
3154 asl_msg_t
*msg
= (asl_msg_t
*)obj
;
3157 asl_msg_t
*next
= msg
->next
;
3158 _asl_msg_free_page(msg
);
3164 _jump_set_key_val_op(asl_object_private_t
*obj
, const char *key
, const char *val
, uint16_t op
)
3167 int status
= asl_msg_set_key_val_op((asl_msg_t
*)obj
, key
, val
, op32
);
3168 return (status
== ASL_STATUS_OK
) ? 0 : -1;
3172 _jump_unset_key(asl_object_private_t
*obj
, const char *key
)
3174 asl_msg_unset((asl_msg_t
*)obj
, key
);
3178 _jump_get_val_op_for_key(asl_object_private_t
*obj
, const char *key
, const char **val
, uint16_t *op
)
3180 return asl_msg_lookup((asl_msg_t
*)obj
, key
, val
, op
);
3184 _jump_get_key_val_op_at_index(asl_object_private_t
*obj
, size_t n
, const char **key
, const char **val
, uint16_t *op
)
3186 uint32_t slot
= IndexNull
;
3187 asl_msg_t
*page
= NULL
;
3189 if (0 != _asl_msg_resolve_index((asl_msg_t
*)obj
, n
, &page
, &slot
)) return -1;
3191 if (key
!= NULL
) *key
= _asl_msg_slot_key(page
, slot
);
3192 if (val
!= NULL
) *val
= _asl_msg_slot_val(page
, slot
);
3193 if (op
!= NULL
) *op
= _get_slot_op(page
, slot
);
3199 _jump_count(asl_object_private_t
*obj
)
3201 size_t count
= asl_msg_count((asl_msg_t
*)obj
);
3206 _jump_append(asl_object_private_t
*obj
, asl_object_private_t
*newobj
, void *addr
)
3208 int type
= asl_get_type((asl_object_t
)newobj
);
3209 if ((type
!= ASL_TYPE_QUERY
) && (type
!= ASL_TYPE_MSG
)) return;
3211 asl_msg_merge((asl_msg_t
*)obj
, (asl_msg_t
*)newobj
);
3215 _jump_prepend(asl_object_private_t
*obj
, asl_object_private_t
*newobj
)
3217 if (obj
== NULL
) return;
3219 int type
= asl_get_type((asl_object_t
)newobj
);
3220 if ((type
!= ASL_TYPE_QUERY
) && (type
!= ASL_TYPE_MSG
)) return;
3222 asl_msg_replace((asl_msg_t
*)obj
, (asl_msg_t
*)newobj
);
3225 static asl_object_private_t
*
3226 _jump_search(asl_object_private_t
*obj
, asl_object_private_t
*query
)
3228 if (obj
== NULL
) return NULL
;
3232 /* NULL matches any message */
3233 asl_msg_list_t
*out
= asl_msg_list_new();
3234 asl_msg_list_append(out
, obj
);
3235 return (asl_object_private_t
*)out
;
3238 if ((query
->asl_type
!= ASL_TYPE_MSG
) && (query
->asl_type
!= ASL_TYPE_QUERY
)) return NULL
;
3240 if (asl_msg_cmp((asl_msg_t
*)obj
, (asl_msg_t
*)query
) == 1)
3242 asl_msg_list_t
*out
= asl_msg_list_new();
3243 asl_msg_list_append(out
, obj
);
3244 return (asl_object_private_t
*)out
;
3250 static asl_object_private_t
*
3251 _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
)
3253 if (obj
== NULL
) return NULL
;
3257 /* NULL matches any message */
3258 asl_msg_list_t
*out
= asl_msg_list_new();
3259 asl_msg_list_append(out
, obj
);
3260 return (asl_object_private_t
*)out
;
3263 if (asl_msg_cmp_list((asl_msg_t
*)obj
, (asl_msg_list_t
*)qlist
) == 0) return NULL
;
3265 asl_msg_list_t
*out
= asl_msg_list_new();
3266 asl_msg_list_append(out
, obj
);
3267 return (asl_object_private_t
*)out
;
3271 __private_extern__
const asl_jump_table_t
*
3272 asl_msg_jump_table()
3274 static const asl_jump_table_t jump
=
3276 .alloc
= &_jump_alloc
,
3277 .dealloc
= &_jump_dealloc
,
3278 .set_key_val_op
= &_jump_set_key_val_op
,
3279 .unset_key
= &_jump_unset_key
,
3280 .get_val_op_for_key
= &_jump_get_val_op_for_key
,
3281 .get_key_val_op_at_index
= &_jump_get_key_val_op_at_index
,
3282 .count
= &_jump_count
,
3285 .get_object_at_index
= NULL
,
3286 .set_iteration_index
= NULL
,
3287 .remove_object_at_index
= NULL
,
3288 .append
= &_jump_append
,
3289 .prepend
= &_jump_prepend
,
3290 .search
= &_jump_search
,
3291 .match
= &_jump_match