2 * Copyright (c) 2009-2011 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@
37 #include <asl_private.h>
39 #include <sys/types.h>
40 #include <libkern/OSAtomic.h>
57 #define SEC_PER_HOUR 3600
59 #define forever for(;;)
61 #define streq(A, B) (strcmp(A, B) == 0)
62 #define streq_len(A, B, C) (strncmp(A, B, C) == 0)
63 #define strneq(A, B) (strcmp(A, B) != 0)
64 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
65 #define strcaseneq(A, B) (strcasecmp(A, B) != 0)
67 #ifndef ASL_KEY_OPTION
68 #define ASL_KEY_OPTION "ASLOption"
71 #ifndef ASL_QUERY_OP_FALSE
72 #define ASL_QUERY_OP_FALSE 0
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
87 extern time_t asl_parse_time(const char *in
);
90 int asl_is_utf8(const char *str
);
91 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
93 static const char *ASLStandardKey
[] =
115 static const char *MTStandardKey
[] =
117 "com.apple.message.domain",
118 "com.apple.message.domain_scope",
119 "com.apple.message.result",
120 "com.apple.message.signature",
121 "com.apple.message.signature2",
122 "com.apple.message.signature3",
123 "com.apple.message.success",
124 "com.apple.message.uuid",
125 "com.apple.message.value",
126 "com.apple.message.value2",
127 "com.apple.message.value3",
128 "com.apple.message.value4",
129 "com.apple.message.value5"
133 _asl_msg_std_key(const char *s
, uint32_t len
)
135 if ((len
> 18) && (streq_len(s
, "com.apple.message.", 18)))
137 if (streq(s
+ 18, "domain")) return ASL_MT_KEY_DOMAIN
;
138 else if (streq(s
+ 18, "domain_scope")) return ASL_MT_KEY_SCOPE
;
139 else if (streq(s
+ 18, "result")) return ASL_MT_KEY_RESULT
;
140 else if (streq(s
+ 18, "signature")) return ASL_MT_KEY_SIG
;
141 else if (streq(s
+ 18, "signature2")) return ASL_MT_KEY_SIG2
;
142 else if (streq(s
+ 18, "signature3")) return ASL_MT_KEY_SIG3
;
143 else if (streq(s
+ 18, "success")) return ASL_MT_KEY_SUCCESS
;
144 else if (streq(s
+ 18, "uuid")) return ASL_MT_KEY_UUID
;
145 else if (streq(s
+ 18, "value")) return ASL_MT_KEY_VAL
;
146 else if (streq(s
+ 18, "value2")) return ASL_MT_KEY_VAL2
;
147 else if (streq(s
+ 18, "value3")) return ASL_MT_KEY_VAL3
;
148 else if (streq(s
+ 18, "value4")) return ASL_MT_KEY_VAL4
;
149 else if (streq(s
+ 18, "value5")) return ASL_MT_KEY_VAL5
;
158 if streq(s
, ASL_KEY_PID
) return ASL_STD_KEY_PID
;
159 else if streq(s
, ASL_KEY_UID
) return ASL_STD_KEY_UID
;
160 else if streq(s
, ASL_KEY_GID
) return ASL_STD_KEY_GID
;
164 if streq(s
, ASL_KEY_TIME
) return ASL_STD_KEY_TIME
;
165 else if streq(s
, ASL_KEY_HOST
) return ASL_STD_KEY_HOST
;
169 if streq(s
, ASL_KEY_LEVEL
) return ASL_STD_KEY_LEVEL
;
173 if streq(s
, ASL_KEY_SENDER
) return ASL_STD_KEY_SENDER
;
174 else if streq(s
, ASL_KEY_REF_PID
) return ASL_STD_KEY_REF_PID
;
178 if streq(s
, ASL_KEY_MSG
) return ASL_STD_KEY_MESSAGE
;
179 else if streq(s
, ASL_KEY_SESSION
) return ASL_STD_KEY_SESSION
;
180 else if streq(s
, ASL_KEY_READ_UID
) return ASL_STD_KEY_READ_UID
;
181 else if streq(s
, ASL_KEY_READ_GID
) return ASL_STD_KEY_READ_GID
;
182 else if streq(s
, ASL_KEY_REF_PROC
) return ASL_STD_KEY_REF_PROC
;
186 if streq(s
, ASL_KEY_FACILITY
) return ASL_STD_KEY_FACILITY
;
190 if streq(s
, ASL_KEY_OPTION
) return ASL_STD_KEY_OPTION
;
194 if streq(s
, ASL_KEY_TIME_NSEC
) return ASL_STD_KEY_NANO
;
198 if streq(s
, ASL_KEY_MSG_ID
) return ASL_STD_KEY_MSG_ID
;
202 if streq(s
, ASL_KEY_EXPIRE_TIME
) return ASL_STD_KEY_EXPIRE
;
219 out
= calloc(1, sizeof(asl_msg_t
));
220 if (out
== NULL
) return NULL
;
222 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
224 out
->key
[i
] = ASL_MSG_SLOT_FREE
;
225 out
->val
[i
] = ASL_MSG_SLOT_FREE
;
232 _asl_msg_slot_key(asl_msg_t
*page
, uint32_t slot
)
237 if (page
== NULL
) return NULL
;
238 if (slot
>= ASL_MSG_PAGE_SLOTS
) return NULL
;
240 if (page
->key
[slot
] == ASL_MSG_SLOT_FREE
) return NULL
;
242 switch (page
->key
[slot
] & ASL_MSG_KV_MASK
)
244 case ASL_MSG_KV_INLINE
:
246 return page
->data
+ page
->key
[slot
];
248 case ASL_MSG_KV_DICT
:
250 if ((page
->key
[slot
] > ASL_STD_KEY_BASE
) && (page
->key
[slot
] <= ASL_STD_KEY_LAST
))
252 x
= page
->key
[slot
] - ASL_STD_KEY_BASE
- 1;
253 return ASLStandardKey
[x
];
255 else if ((page
->key
[slot
] > ASL_MT_KEY_BASE
) && (page
->key
[slot
] <= ASL_MT_KEY_LAST
))
257 x
= page
->key
[slot
] - ASL_MT_KEY_BASE
- 1;
258 return MTStandardKey
[x
];
263 case ASL_MSG_KV_EXTERN
:
265 x
= page
->key
[slot
] & ASL_MSG_OFFSET_MASK
;
266 memcpy(&out
, page
->data
+ x
, sizeof(char *));
275 _asl_msg_slot_val(asl_msg_t
*page
, uint32_t slot
)
280 if (page
== NULL
) return NULL
;
281 if (slot
>= ASL_MSG_PAGE_SLOTS
) return NULL
;
283 if (page
->val
[slot
] == ASL_MSG_SLOT_FREE
) return NULL
;
285 type
= page
->val
[slot
] & ASL_MSG_KV_MASK
;
287 if (type
== ASL_MSG_KV_INLINE
)
289 return page
->data
+ page
->val
[slot
];
291 else if (type
== ASL_MSG_KV_EXTERN
)
293 x
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
294 memcpy(&out
, page
->data
+ x
, sizeof(char *));
302 * asl_new: create a new log message.
305 asl_msg_new(uint32_t type
)
309 out
= _asl_msg_make_page();
310 if (out
== NULL
) return NULL
;
319 asl_msg_retain(asl_msg_t
*msg
)
323 if (msg
== NULL
) return NULL
;
325 new = OSAtomicIncrement32Barrier(&msg
->refcount
);
332 _asl_msg_free(asl_msg_t
*page
)
337 if (page
== NULL
) return;
339 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
341 if ((page
->key
[i
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
343 memcpy(&p
, page
->data
+ (page
->key
[i
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
347 if ((page
->val
[i
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
349 memcpy(&p
, page
->data
+ (page
->val
[i
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
358 asl_msg_release(asl_msg_t
*msg
)
363 if (msg
== NULL
) return;
365 new = OSAtomicDecrement32Barrier(&msg
->refcount
);
379 _asl_msg_index(asl_msg_t
*msg
, const char *key
, uint32_t *oslot
, asl_msg_t
**opage
)
381 uint32_t i
, len
, slot
;
386 if (msg
== NULL
) return IndexNull
;
387 if (key
== NULL
) return IndexNull
;
391 if (oslot
!= NULL
) *oslot
= slot
;
394 if (opage
!= NULL
) *opage
= page
;
397 kx
= _asl_msg_std_key(key
, len
);
401 if (page
->key
[slot
] != ASL_MSG_SLOT_FREE
)
405 if (page
->key
[slot
] == kx
) return i
;
407 else if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
)
409 /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
411 else if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
413 memcpy(&kp
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
414 if (streq(key
, kp
)) return i
;
418 kp
= page
->data
+ page
->key
[slot
];
419 if (streq(key
, kp
)) return i
;
425 if (oslot
!= NULL
) *oslot
= slot
;
427 if (slot
>= ASL_MSG_PAGE_SLOTS
)
429 if (page
->next
== NULL
) return IndexNull
;
432 if (oslot
!= NULL
) *oslot
= slot
;
435 if (opage
!= NULL
) *opage
= page
;
443 * asl_msg_key: iterate over entries
444 * initial value of n should be 0
445 * after that, the value of n should be previously returned value
446 * sets the pointers for the next key, value, and op in the msgionary
447 * returns IndexNull when there are no more entries
450 _asl_msg_fetch_internal(asl_msg_t
*msg
, uint32_t n
, const char **keyout
, const char **valout
, uint32_t *opout
, asl_msg_t
**outpage
, uint32_t *outslot
)
455 if (msg
== NULL
) return IndexNull
;
456 if (outpage
!= NULL
) *outpage
= NULL
;
457 if (outslot
!= NULL
) *outslot
= IndexNull
;
462 while (slot
>= ASL_MSG_PAGE_SLOTS
)
464 if (page
->next
== NULL
) return IndexNull
;
466 slot
-= ASL_MSG_PAGE_SLOTS
;
469 while (page
->key
[slot
] == ASL_MSG_SLOT_FREE
)
474 if (slot
>= ASL_MSG_PAGE_SLOTS
)
476 if (page
->next
== NULL
) return IndexNull
;
484 if (keyout
!= NULL
) *keyout
= _asl_msg_slot_key(page
, slot
);
485 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, slot
);
486 if (opout
!= NULL
) *opout
= page
->op
[slot
];
488 if (outpage
!= NULL
) *outpage
= page
;
489 if (outslot
!= NULL
) *outslot
= slot
;
495 asl_msg_fetch(asl_msg_t
*msg
, uint32_t n
, const char **keyout
, const char **valout
, uint32_t *opout
)
497 return _asl_msg_fetch_internal(msg
, n
, keyout
, valout
, opout
, NULL
, NULL
);
501 _asl_msg_new_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
503 uint32_t slot
, keylen
, vallen
, total
;
505 asl_msg_t
*page
, *last
;
506 char *extkey
, *extval
;
508 if (msg
== NULL
) return -1;
509 if (key
== NULL
) return -1;
514 keylen
= strlen(key
);
515 kx
= _asl_msg_std_key(key
, keylen
);
517 if (kx
== 0) keylen
++;
525 vallen
= strlen(val
) + 1;
529 /* check if one or both of key and value must be "external" (in its own malloced space) */
530 if (keylen
> ASL_MSG_PAGE_DATA_SIZE
)
532 extkey
= strdup(key
);
533 keylen
= sizeof(char *);
536 if (vallen
> ASL_MSG_PAGE_DATA_SIZE
)
538 extval
= strdup(val
);
539 vallen
= sizeof(char *);
542 total
= keylen
+ vallen
;
543 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extval
== NULL
) && (keylen
> 0))
545 extval
= strdup(val
);
546 vallen
= sizeof(char *);
547 total
= keylen
+ vallen
;
550 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extkey
== NULL
))
552 extkey
= strdup(key
);
553 keylen
= sizeof(char *);
554 total
= keylen
+ vallen
;
557 if (total
> ASL_MSG_PAGE_DATA_SIZE
)
559 /* can't happen, but... */
560 if (extkey
!= NULL
) free(extkey
);
561 if (extval
!= NULL
) free(extval
);
565 /* find a page with space for the key and value and a free slot*/
569 for (page
= msg
; page
!= NULL
; page
= page
->next
)
573 if (total
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
575 /* check for a free slot */
576 for (slot
= 0; (slot
< ASL_MSG_PAGE_SLOTS
) && (page
->key
[slot
] != ASL_MSG_SLOT_FREE
); slot
++);
577 if (slot
< ASL_MSG_PAGE_SLOTS
) break;
583 /* allocate a new page and attach it */
584 page
= _asl_msg_make_page();
587 if (extkey
!= NULL
) free(extkey
);
588 if (extval
!= NULL
) free(extval
);
596 /* copy key or external key pointer into page data */
599 page
->key
[slot
] = kx
;
601 else if (extkey
== NULL
)
603 page
->key
[slot
] = page
->data_size
;
604 memcpy(page
->data
+ page
->data_size
, key
, keylen
);
608 page
->key
[slot
] = page
->data_size
| ASL_MSG_KV_EXTERN
;
609 memcpy(page
->data
+ page
->data_size
, &extkey
, keylen
);
612 page
->data_size
+= keylen
;
614 /* copy val or external val pointer into page data */
615 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
621 page
->val
[slot
] = page
->data_size
;
622 memcpy(page
->data
+ page
->data_size
, val
, vallen
);
626 page
->val
[slot
] = page
->data_size
| ASL_MSG_KV_EXTERN
;
627 memcpy(page
->data
+ page
->data_size
, &extval
, vallen
);
630 page
->data_size
+= vallen
;
636 /* update page count */
643 * Most of the code in asl_msg_set_key_val_op is concerned with trying to re-use
644 * space in an asl_msg_t page when given a new value for an existing key.
645 * If the key is new, we just call _asl_msg_new_key_val_op.
647 * Note that queries can have duplicate keys, so for ASL_TYPE_QUERY we just
648 * call through to _asl_msg_new_key_val_op.
651 _asl_msg_set_kvo(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
653 uint32_t i
, slot
, newexternal
;
655 uint32_t intvallen
, extvallen
, newvallen
;
656 char *intval
, *extval
, *newval
;
658 if (msg
== NULL
) return -1;
659 if (key
== NULL
) return -1;
664 if ((msg
->type
== ASL_TYPE_QUERY
) || (IndexNull
== _asl_msg_index(msg
, key
, &slot
, &page
)))
667 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
676 if (page
->val
[slot
] != ASL_MSG_SLOT_FREE
)
678 if ((page
->val
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
680 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
681 memcpy(&extval
, page
->data
+ i
, sizeof(char *));
682 extvallen
= sizeof(char *);
686 intval
= page
->data
+ page
->val
[slot
];
687 intvallen
= strlen(intval
) + 1;
691 /* replace val and op for existing entry */
693 /* easy case - remove val */
696 if (extval
!= NULL
) free(extval
);
697 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
698 if (op
!= IndexNull
) page
->op
[slot
] = op
;
702 /* trivial case - internal val doesn't change */
703 if ((intval
!= NULL
) && (streq(val
, intval
)))
705 if (op
!= IndexNull
) page
->op
[slot
] = op
;
709 /* trivial case - external val doesn't change */
710 if ((extval
!= NULL
) && (streq(val
, extval
)))
712 if (op
!= IndexNull
) page
->op
[slot
] = op
;
717 * special case: we generally don't compress out holes in the data
718 * space, but if this is the last string in the currently used data space
719 * we can just back up the data_size and reset page->val[slot]
721 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
722 if ((intval
!= NULL
) && ((i
+ intvallen
) == page
->data_size
))
724 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
725 page
->data_size
-= intvallen
;
729 else if ((extval
!= NULL
) && ((i
+ extvallen
) == page
->data_size
))
731 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
732 page
->data_size
-= extvallen
;
738 /* val changes - see if it needs to be external */
739 newvallen
= strlen(val
) + 1;
742 if (newvallen
> ASL_MSG_PAGE_DATA_SIZE
)
745 newvallen
= sizeof(char *);
748 /* check if there is room to change val in place */
749 if (((extval
!= NULL
) && (newvallen
<= extvallen
)) || ((extval
== NULL
) && (newvallen
<= intvallen
)))
751 if (extval
!= NULL
) free(extval
);
754 /* we can re-use the space of the old value */
755 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
757 if (newexternal
== 1)
759 /* create an external val and copy in the new pointer */
760 newval
= strdup(val
);
761 if (newval
== NULL
) return -1;
763 page
->val
[slot
] = i
| ASL_MSG_KV_EXTERN
;
764 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
768 /* new internal value */
770 memcpy(page
->data
+ i
, val
, newvallen
);
773 if (op
!= IndexNull
) page
->op
[slot
] = op
;
777 /* we're done with the old value if it is external - free it now */
778 if (extval
!= NULL
) free(extval
);
781 if (newvallen
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
783 /* can't re-use the old space, but there's room on the page */
785 page
->data_size
+= newvallen
;
787 if (newexternal
== 1)
789 /* create an external val and copy in the new pointer */
790 newval
= strdup(val
);
791 if (newval
== NULL
) return -1;
793 page
->val
[slot
] = i
| ASL_MSG_KV_EXTERN
;
794 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
798 /* new internal value */
800 memcpy(page
->data
+ i
, val
, newvallen
);
803 if (op
!= IndexNull
) page
->op
[slot
] = op
;
808 /* no room on this page - free up existing entry and treat this as a new entry */
809 if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
811 memcpy(&extval
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
815 page
->key
[slot
] = ASL_MSG_SLOT_FREE
;
816 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
819 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
823 asl_msg_set_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
825 char *special
, buf
[512];
829 /* Special case handling */
832 /* convert "Level" values to "0" through "7" */
833 if (streq(key
, ASL_KEY_LEVEL
))
835 if (val
== NULL
) val
= "7";
836 else if ((val
[0] >= '0') && (val
[0] <= '7') && (val
[1] == '\0')) /* do nothing */;
837 else if (strcaseeq(val
, ASL_STRING_EMERG
)) val
= "0";
838 else if (strcaseeq(val
, ASL_STRING_ALERT
)) val
= "1";
839 else if (strcaseeq(val
, ASL_STRING_CRIT
)) val
= "2";
840 else if (strcaseeq(val
, ASL_STRING_ERR
)) val
= "3";
841 else if (strcaseeq(val
, ASL_STRING_WARNING
)) val
= "4";
842 else if (strcaseeq(val
, ASL_STRING_NOTICE
)) val
= "5";
843 else if (strcaseeq(val
, ASL_STRING_INFO
)) val
= "6";
844 else if (strcaseeq(val
, ASL_STRING_DEBUG
)) val
= "7";
848 /* strip trailing newlines from "Message" values */
849 if ((streq(key
, ASL_KEY_MSG
)) && (val
!= NULL
))
853 while ((i
> 0) && (val
[i
- 1] == '\n')) i
--;
854 if (i
== 0) val
= NULL
;
857 /* use buf if it is big enough, else malloc a temporary buffer */
862 val
= (const char *)buf
;
866 special
= malloc(i
+ 1);
867 if (special
== NULL
) return -1;
868 memcpy(special
, val
, i
);
870 val
= (const char *)special
;
875 status
= _asl_msg_set_kvo(msg
, key
, val
, op
);
877 if (special
!= NULL
) free(special
);
882 asl_msg_set_key_val(asl_msg_t
*msg
, const char *key
, const char *val
)
884 return asl_msg_set_key_val_op(msg
, key
, val
, 0);
888 * Merge a key / val into a message (only ASL_TYPE_MSG).
889 * Adds the key / val if the key is not found.
890 * Does not replace the value if the key is found.
893 _asl_msg_merge_key_val(asl_msg_t
*msg
, const char *key
, const char *val
)
898 if (msg
== NULL
) return;
899 if (key
== NULL
) return;
904 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
905 if (i
!= IndexNull
) return;
907 asl_msg_set_key_val_op(msg
, key
, val
, 0);
911 * Merge msg into target (does not replace existing keys).
912 * Creates a new asl_msg_t if target is NULL.
916 asl_msg_merge(asl_msg_t
*target
, asl_msg_t
*msg
)
918 uint32_t x
, slot
, op
, isnew
= 0;
919 const char *key
, *val
;
922 if (msg
== NULL
) return target
;
927 target
= asl_msg_new(ASL_TYPE_MSG
);
930 for (x
= _asl_msg_fetch_internal(msg
, 0, &key
, &val
, &op
, &page
, &slot
); x
!= IndexNull
; x
= _asl_msg_fetch_internal(msg
, x
, &key
, &val
, &op
, &page
, &slot
))
932 if (isnew
== 1) asl_msg_set_key_val_op(target
, key
, val
, 0);
933 else _asl_msg_merge_key_val(target
, key
, val
);
943 asl_msg_copy(asl_msg_t
*msg
)
945 return asl_msg_merge(NULL
, msg
);
950 * Frees external key and val strings, but does not try to reclaim data space.
953 asl_msg_unset(asl_msg_t
*msg
, const char *key
)
959 if (msg
== NULL
) return;
960 if (key
== NULL
) return;
965 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
966 if (i
== IndexNull
) return;
968 if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
970 memcpy(&ext
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
974 if ((page
->val
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
976 memcpy(&ext
, page
->data
+ (page
->val
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
980 page
->key
[slot
] = ASL_MSG_SLOT_FREE
;
981 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
988 asl_msg_lookup(asl_msg_t
*msg
, const char *key
, const char **valout
, uint32_t *opout
)
996 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
997 if (i
== IndexNull
) return -1;
999 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, slot
);
1000 if (opout
!= NULL
) *opout
= page
->op
[slot
];
1006 asl_msg_type(asl_msg_t
*msg
)
1008 if (msg
== NULL
) return 0;
1013 asl_msg_count(asl_msg_t
*msg
)
1019 for (; msg
!= NULL
; msg
= msg
->next
) total
+= msg
->count
;
1027 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1030 const char *key
, *va
, *vb
;
1032 if (asl_msg_count(a
) != asl_msg_count(b
)) return 0;
1039 for (x
= asl_msg_fetch(a
, 0, &key
, &va
, &oa
); x
!= IndexNull
; x
= asl_msg_fetch(a
, x
, &key
, &va
, &oa
))
1041 if (asl_msg_lookup(b
, key
, &vb
, &ob
) != 0) return 0;
1042 if (strcmp(va
, vb
)) return 0;
1043 if ((a
->type
== ASL_TYPE_QUERY
) && (oa
!= ob
)) return 0;
1050 _asl_isanumber(const char *s
)
1054 if (s
== NULL
) return 0;
1057 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1059 if (s
[i
] == '\0') return 0;
1061 for (; s
[i
] != '\0'; i
++)
1063 if (!isdigit(s
[i
])) return 0;
1070 _asl_msg_basic_test(uint32_t op
, const char *q
, const char *m
, uint32_t n
)
1078 t
= op
& ASL_QUERY_OP_TRUE
;
1080 /* NULL value from query or message string fails */
1081 if ((q
== NULL
) || (m
== NULL
)) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1083 if (op
& ASL_QUERY_OP_REGEX
)
1085 /* greater than or less than make no sense in substring search */
1086 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1088 memset(&rex
, 0, sizeof(regex_t
));
1090 rflags
= REG_EXTENDED
| REG_NOSUB
;
1091 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1093 /* A bad reqular expression matches nothing */
1094 if (regcomp(&rex
, q
, rflags
) != 0) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1096 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1099 if (t
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp
!= 0);
1103 if (op
& ASL_QUERY_OP_NUMERIC
)
1105 if (_asl_isanumber(q
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1106 if (_asl_isanumber(m
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1113 case ASL_QUERY_OP_EQUAL
: return (nm
== nq
);
1114 case ASL_QUERY_OP_GREATER
: return (nm
> nq
);
1115 case ASL_QUERY_OP_GREATER_EQUAL
: return (nm
>= nq
);
1116 case ASL_QUERY_OP_LESS
: return (nm
< nq
);
1117 case ASL_QUERY_OP_LESS_EQUAL
: return (nm
<= nq
);
1118 case ASL_QUERY_OP_NOT_EQUAL
: return (nm
!= nq
);
1119 default: return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1124 if (op
& ASL_QUERY_OP_CASEFOLD
)
1126 if (n
== 0) cmp
= strcasecmp(m
, q
);
1127 else cmp
= strncasecmp(m
, q
, n
);
1131 if (n
== 0) cmp
= strcmp(m
, q
);
1132 else cmp
= strncmp(m
, q
, n
);
1137 case ASL_QUERY_OP_EQUAL
: return (cmp
== 0);
1138 case ASL_QUERY_OP_GREATER
: return (cmp
> 0);
1139 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp
>= 0);
1140 case ASL_QUERY_OP_LESS
: return (cmp
< 0);
1141 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp
<= 0);
1142 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp
!= 0);
1145 return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1149 _asl_msg_test_substring(uint32_t op
, const char *q
, const char *m
)
1151 uint32_t t
, i
, d
, lm
, lq
, match
, newop
;
1153 t
= op
& ASL_QUERY_OP_TRUE
;
1156 if (m
!= NULL
) lm
= strlen(m
);
1159 if (q
!= NULL
) lq
= strlen(q
);
1161 /* NULL is a substring of any string */
1162 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1164 /* A long string is defined to be not equal to a short string */
1165 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1167 /* greater than or less than make no sense in substring search */
1168 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1171 * We scan the string doing an equality test.
1172 * If the input test is equality, we stop as soon as we hit a match.
1173 * Otherwise we keep scanning the whole message string.
1176 newop
|= ASL_QUERY_OP_EQUAL
;
1180 for (i
= 0; i
<= d
; i
++)
1182 if (_asl_msg_basic_test(newop
, q
, m
+ i
, lq
) != 0)
1184 if (t
& ASL_QUERY_OP_EQUAL
) return 1;
1189 /* If the input test was for equality, no matches were found */
1190 if (t
& ASL_QUERY_OP_EQUAL
) return 0;
1192 /* The input test was for not equal. Return true if no matches were found */
1193 return (match
== 0);
1197 _asl_msg_test_prefix(uint32_t op
, const char *q
, const char *m
)
1201 t
= op
& ASL_QUERY_OP_TRUE
;
1204 if (m
!= NULL
) lm
= strlen(m
);
1207 if (q
!= NULL
) lq
= strlen(q
);
1209 /* NULL is a prefix of any string */
1210 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1212 /* A long string is defined to be not equal to a short string */
1213 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1215 /* Compare two equal-length strings */
1216 return _asl_msg_basic_test(op
, q
, m
, lq
);
1220 _asl_msg_test_suffix(uint32_t op
, const char *q
, const char *m
)
1222 uint32_t lm
, lq
, d
, t
;
1224 t
= op
& ASL_QUERY_OP_TRUE
;
1227 if (m
!= NULL
) lm
= strlen(m
);
1230 if (q
!= NULL
) lq
= strlen(q
);
1232 /* NULL is a suffix of any string */
1233 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1235 /* A long string is defined to be not equal to a short string */
1236 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1238 /* Compare two equal-length strings */
1240 return _asl_msg_basic_test(op
, q
, m
+ d
, lq
);
1244 * Splits out prefix, suffix, and substring tests.
1245 * Sends the rest to _asl_msg_basic_test().
1248 _asl_msg_test_expression(uint32_t op
, const char *q
, const char *m
)
1252 t
= op
& ASL_QUERY_OP_TRUE
;
1253 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1255 if (op
& ASL_QUERY_OP_PREFIX
)
1257 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
);
1258 return _asl_msg_test_prefix(op
, q
, m
);
1260 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
);
1262 return _asl_msg_basic_test(op
, q
, m
, 0);
1266 * Special case for comparing time values.
1267 * If both inputs are time strings, this compares the time
1268 * value in seconds. Otherwise it just does normal matching.
1271 _asl_msg_test_time_expression(uint32_t op
, const char *q
, const char *m
)
1276 if ((op
& ASL_QUERY_OP_PREFIX
) || (op
& ASL_QUERY_OP_SUFFIX
) || (op
& ASL_QUERY_OP_REGEX
)) return _asl_msg_test_expression(op
, q
, m
);
1277 if ((q
== NULL
) || (m
== NULL
)) return _asl_msg_test_expression(op
, q
, m
);
1279 tq
= asl_parse_time(q
);
1280 if (tq
< 0) return _asl_msg_test_expression(op
, q
, m
);
1282 tm
= asl_parse_time(m
);
1283 if (tm
< 0) return _asl_msg_test_expression(op
, q
, m
);
1285 t
= op
& ASL_QUERY_OP_TRUE
;
1289 case ASL_QUERY_OP_FALSE
:
1293 case ASL_QUERY_OP_EQUAL
:
1295 if (tm
== tq
) return 1;
1298 case ASL_QUERY_OP_GREATER
:
1300 if (tm
> tq
) return 1;
1303 case ASL_QUERY_OP_GREATER_EQUAL
:
1305 if (tm
>= tq
) return 1;
1308 case ASL_QUERY_OP_LESS
:
1310 if (tm
< tq
) return 1;
1313 case ASL_QUERY_OP_LESS_EQUAL
:
1315 if (tm
<= tq
) return 1;
1318 case ASL_QUERY_OP_NOT_EQUAL
:
1320 if (tm
!= tq
) return 1;
1323 case ASL_QUERY_OP_TRUE
:
1333 /* test a query against a message */
1335 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
1337 uint32_t i
, t
, x
, op
;
1339 const char *kq
, *vq
, *vm
;
1342 * Check each simple expression (key op val) separately.
1343 * The query suceeds (returns 1) if all simple expressions
1344 * succeed (i.e. AND the simple expressions).
1351 for (x
= asl_msg_fetch(q
, 0, &kq
, &vq
, &op
); x
!= IndexNull
; x
= asl_msg_fetch(q
, x
, &kq
, &vq
, &op
))
1353 /* Find query key in the message */
1355 i
= asl_msg_lookup(m
, kq
, &vm
, NULL
);
1357 /* ASL_QUERY_OP_TRUE tests if key is present in the message */
1358 t
= op
& ASL_QUERY_OP_TRUE
;
1359 if (t
== ASL_QUERY_OP_TRUE
)
1361 if (i
!= 0) return 0;
1365 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1366 if (t
== ASL_QUERY_OP_FALSE
)
1368 if (i
== 0) return 0;
1374 /* the message does NOT have query key - fail unless we are testing not equal */
1375 if (t
== ASL_QUERY_OP_NOT_EQUAL
) continue;
1380 if (streq(kq
, ASL_KEY_TIME
))
1382 cmp
= _asl_msg_test_time_expression(op
, vq
, vm
);
1386 cmp
= _asl_msg_test_expression(op
, vq
, vm
);
1389 if (cmp
== 0) return 0;
1396 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1399 if (a
== NULL
) return 0;
1400 if (b
== NULL
) return 0;
1402 if (a
->type
== b
->type
) return _asl_msg_equal(a
, b
);
1403 if (a
->type
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
);
1404 return _asl_msg_test(b
, a
);
1409 _asl_time_string(const char *fmt
, const char *str
)
1418 const char *p
= fmt
;
1421 if (str
!= NULL
) tick
= asl_parse_time(str
);
1423 /* default format is local time zone */
1424 if ((fmt
== NULL
) || (!strcasecmp(fmt
, "lcl")) || (!strcasecmp(fmt
, "local")))
1426 ltime
= ctime_r(&tick
, ltbuf
);
1427 if (ltime
== NULL
) return NULL
;
1429 asprintf(&out
, "%s", ltime
+ 4);
1433 if ((!strcasecmp(fmt
, "sec")) || (!strcasecmp(fmt
, "raw")))
1435 asprintf(&out
, "%lu", tick
);
1439 if (!strcasecmp(fmt
, "j"))
1441 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1442 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
);
1446 if ((!strcasecmp(fmt
, "utc")) || (!strcasecmp(fmt
, "zulu")))
1448 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1449 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02dZ", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
);
1453 if ((fmt
[1] == '\0') && (((fmt
[0] >= 'a') && (fmt
[0] <= 'z')) || ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))))
1456 if (z
>= 'a') z
-= 32;
1458 if (z
== 'Z') off
= 0;
1459 else if ((z
>= 'A') && (z
<= 'I')) off
= ((z
- 'A') + 1) * SEC_PER_HOUR
;
1460 else if ((z
>= 'K') && (z
<= 'M')) off
= (z
- 'A') * SEC_PER_HOUR
;
1461 else if ((z
>= 'N') && (z
<= 'Y')) off
= ('M' - z
) * SEC_PER_HOUR
;
1466 if ((*p
== '-') || (*p
== '+')) p
++;
1467 if ((*p
) >= '0' && (*p
<= '9'))
1470 if (fmt
[0] == '-') off
*= -1;
1471 off
*= SEC_PER_HOUR
;
1477 if (fmt
[0] == '-') min
*= -1;
1490 memset(&stm
, 0, sizeof (struct tm
));
1491 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1493 if ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))
1495 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%c", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, fmt
[0]);
1497 else if ((fmt
[0] >= 'a') && (fmt
[0] <= 'z'))
1499 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%c", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, fmt
[0] - 32);
1501 else if ((fmt
[0] >= '0') && (fmt
[0] <= '9'))
1503 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
, fmt
);
1507 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
, fmt
);
1513 /* called from asl_format_message and _asl_send_message */
1514 __private_extern__ asl_string_t
*
1515 asl_msg_to_string_raw(uint32_t encoding
, asl_msg_t
*msg
, const char *tfmt
)
1517 uint32_t i
, x
, count
;
1519 const char *key
, *val
;
1522 if (msg
== NULL
) return NULL
;
1524 count
= asl_msg_count(msg
);
1525 if (count
== 0) return NULL
;
1527 str
= asl_string_new(encoding
);
1528 if (str
== NULL
) return NULL
;
1534 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
1536 if (key
== NULL
) continue;
1538 if (i
> 0) asl_string_append_char_no_encoding(str
, ' ');
1540 asl_string_append_char_no_encoding(str
, '[');
1541 asl_string_append_asl_key(str
, key
);
1543 if (!strcmp(key
, ASL_KEY_TIME
))
1545 asl_string_append_char_no_encoding(str
, ' ');
1548 if (val
!= NULL
) vtime
= _asl_time_string(tfmt
, val
);
1552 asl_string_append_no_encoding(str
, vtime
);
1557 asl_string_append_char_no_encoding(str
, '0');
1560 else if (val
!= NULL
)
1562 asl_string_append_char_no_encoding(str
, ' ');
1563 asl_string_append(str
, val
);
1566 asl_string_append_char_no_encoding(str
, ']');
1574 static asl_string_t
*
1575 _asl_string_append_asl_msg(asl_string_t
*str
, asl_msg_t
*msg
)
1577 const char *key
, *val
;
1580 if (msg
== NULL
) return str
;
1582 if (msg
->type
== ASL_TYPE_QUERY
) asl_string_append(str
, "Q ");
1592 i
= asl_msg_fetch(msg
, i
, &key
, &val
, &op
);
1595 if (n
!= 0) asl_string_append_char_no_encoding(str
, ' ');
1598 asl_string_append_char_no_encoding(str
, '[');
1600 if (msg
->type
== ASL_TYPE_QUERY
)
1602 asl_string_append_op(str
, op
);
1603 asl_string_append_char_no_encoding(str
, ' ');
1606 asl_string_append_asl_key(str
, key
);
1610 asl_string_append_char_no_encoding(str
, ' ');
1611 asl_string_append(str
, val
);
1614 asl_string_append_char_no_encoding(str
, ']');
1617 if (i
== IndexNull
) break;
1624 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
1627 asl_string_t
*str
= asl_string_new(ASL_ENCODE_ASL
);
1628 if (str
== NULL
) return NULL
;
1630 str
= _asl_string_append_asl_msg(str
, msg
);
1631 *len
= asl_string_length(str
);
1632 out
= asl_string_free_return_bytes(str
);
1637 _asl_msg_op_from_string(char *o
)
1641 op
= ASL_QUERY_OP_NULL
;
1643 if (o
== NULL
) return op
;
1645 for (i
= 0; o
[i
] != '\0'; i
++)
1647 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
1648 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
1649 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
1650 if (o
[i
] == 'N') op
|= ASL_QUERY_OP_NUMERIC
;
1651 if (o
[i
] == 'S') op
|= ASL_QUERY_OP_SUBSTRING
;
1652 if (o
[i
] == 'A') op
|= ASL_QUERY_OP_PREFIX
;
1653 if (o
[i
] == 'Z') op
|= ASL_QUERY_OP_SUFFIX
;
1654 if (o
[i
] == '<') op
|= ASL_QUERY_OP_LESS
;
1655 if (o
[i
] == '>') op
|= ASL_QUERY_OP_GREATER
;
1656 if (o
[i
] == '=') op
|= ASL_QUERY_OP_EQUAL
;
1657 if (o
[i
] == '!') op
|= ASL_QUERY_OP_NOT_EQUAL
;
1658 if (o
[i
] == 'T') op
|= ASL_QUERY_OP_TRUE
;
1665 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
1667 char *str
, *out
, c
, oval
;
1668 uint32_t i
, len
, n
, outlen
;
1672 if (p
== NULL
) return NULL
;
1673 if (*p
== NULL
) return NULL
;
1674 if (**p
== '\0') return NULL
;
1676 /* skip one space if it's there (word separator) */
1677 if (**p
== ' ') (*p
)++;
1679 /* skip leading white space */
1682 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
1685 if (**p
== '\0') return NULL
;
1686 if (**p
== '\n') return NULL
;
1697 if (out
== NULL
) return NULL
;
1704 /* scan for token and calulate it's length (input and decoded output len) */
1712 /* stop scanning when we hit a delimiter */
1713 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
1719 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
1724 if (str
[++len
] == '\0') return NULL
;
1728 if (str
[++len
] == '\0') return NULL
;
1729 if (str
[++len
] == '\0') return NULL
;
1731 else if ((c
>= '0') && (c
<= '3'))
1733 if (str
[++len
] == '\0') return NULL
;
1734 if (str
[++len
] == '\0') return NULL
;
1748 if ((len
== 0) && (**p
== ']'))
1753 if (out
== NULL
) return NULL
;
1762 out
= malloc(outlen
+ 1);
1763 if (out
== NULL
) return NULL
;
1766 for (i
= 0; i
< len
; i
++)
1823 if (str
[i
] == '?') out
[n
++] = 127;
1824 else out
[n
++] = str
[i
] - 64;
1833 if (str
[i
] == '?') out
[n
++] = 255;
1834 else out
[n
++] = str
[i
] + 64;
1839 out
[n
++] = str
[i
] + 128;
1849 else if ((c
>= '0') && (c
<= '3'))
1851 oval
= (c
- '0') * 64;
1855 if ((c
< '0') || (c
> '7'))
1862 oval
+= ((c
- '0') * 8);
1866 if ((c
< '0') || (c
> '7'))
1887 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
1898 asl_msg_from_string(const char *buf
)
1900 uint32_t tt
, type
, op
;
1901 char *k
, *v
, *o
, *p
;
1904 if (buf
== NULL
) return NULL
;
1906 type
= ASL_TYPE_MSG
;
1909 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1910 if (k
== NULL
) return NULL
;
1914 type
= ASL_TYPE_QUERY
;
1917 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1919 else if (tt
== TOKEN_INT
)
1921 /* Leading integer is a string length - skip it */
1923 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1924 if (k
== NULL
) return NULL
;
1927 out
= asl_msg_new(ASL_TYPE_MSG
);
1928 if (out
== NULL
) return NULL
;
1932 /* OPEN WORD [WORD [WORD]] CLOSE */
1935 op
= ASL_QUERY_OP_NULL
;
1937 if (tt
!= TOKEN_OPEN
)
1939 asl_msg_release(out
);
1945 /* get op for query type */
1946 if (type
== ASL_TYPE_QUERY
)
1948 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
1949 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
1951 if (o
!= NULL
) free(o
);
1952 asl_msg_release(out
);
1956 op
= _asl_msg_op_from_string(o
);
1960 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1961 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1962 if ((k
== NULL
) || (tt
!= TOKEN_WORD
))
1964 if (k
!= NULL
) free(k
);
1965 asl_msg_release(out
);
1969 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
1970 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1973 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
1978 if (tt
== TOKEN_CLOSE
)
1980 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
1982 else if (tt
== TOKEN_WORD
)
1984 asl_msg_set_key_val_op(out
, k
, v
, op
);
1988 if (k
!= NULL
) free(k
);
1989 if (v
!= NULL
) free(v
);
1990 asl_msg_release(out
);
1994 if (k
!= NULL
) free(k
);
1995 if (v
!= NULL
) free(v
);
1997 if (tt
!= TOKEN_CLOSE
)
1999 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2000 if (k
== NULL
) break;
2002 if (tt
!= TOKEN_CLOSE
)
2004 asl_msg_release(out
);
2011 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2012 if (k
== NULL
) break;
2019 asl_list_to_string(asl_search_result_t
*list
, uint32_t *len
)
2024 asl_string_t
*str
= asl_string_new(ASL_ENCODE_ASL
);
2025 if (str
== NULL
) return NULL
;
2027 if (list
== NULL
) return NULL
;
2028 if (list
->count
== 0) return NULL
;
2029 if (list
->msg
== NULL
) return NULL
;
2031 snprintf(tmp
, sizeof(tmp
), "%u", list
->count
);
2032 asl_string_append(str
, tmp
);
2033 asl_string_append_char_no_encoding(str
, '\n');
2035 for (i
= 0; i
< list
->count
; i
++)
2037 _asl_string_append_asl_msg(str
, list
->msg
[i
]);
2038 asl_string_append_char_no_encoding(str
, '\n');
2041 *len
= asl_string_length(str
);
2042 out
= asl_string_free_return_bytes(str
);
2046 asl_search_result_t
*
2047 asl_list_from_string(const char *buf
)
2051 asl_search_result_t
*out
;
2054 if (buf
== NULL
) return NULL
;
2058 if (n
== 0) return NULL
;
2060 out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
2061 if (out
== NULL
) return NULL
;
2063 out
->msg
= (asl_msg_t
**)calloc(n
, sizeof(asl_msg_t
*));
2064 if (out
->msg
== NULL
)
2070 for (i
= 0; i
< n
; i
++)
2072 p
= strchr(p
, '\n');
2075 aslresponse_free((aslresponse
)out
);
2081 m
= asl_msg_from_string(p
);
2084 aslresponse_free((aslresponse
)out
);
2088 out
->msg
[i
] = (asl_msg_t
*)m
;
2096 _asl_level_string(int level
)
2098 if (level
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
;
2099 if (level
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
;
2100 if (level
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
;
2101 if (level
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
;
2102 if (level
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
;
2103 if (level
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
;
2104 if (level
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
;
2105 if (level
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
;
2110 * Find the value for a key in a message and append a formatted value to str.
2111 * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)).
2112 * WARNING: modifies kf!
2114 static asl_string_t
*
2115 _asl_string_append_value_for_key_format(asl_string_t
*str
, asl_msg_t
*msg
, char *kf
, const char *tfmt
)
2117 uint32_t i
, get_fmt
;
2121 if (str
== NULL
) return NULL
;
2122 if (msg
== NULL
) return str
;
2123 if (kf
== NULL
) return str
;
2129 for (i
= 0; kf
[i
] != '\0'; i
++)
2136 else if (kf
[i
] != '(')
2138 if (key
== NULL
) key
= kf
+ i
;
2139 else if ((get_fmt
== 1) && (fmt
== NULL
)) fmt
= kf
+ i
;
2143 if (key
== NULL
) return str
;
2145 asl_msg_lookup(msg
, key
, &mval
, NULL
);
2146 if (mval
== NULL
) return str
;
2148 if (!strcmp(key
, ASL_KEY_TIME
))
2152 /* format in $((Time)(fmt)) overrides tfmt */
2155 fval
= _asl_time_string(tfmt
, mval
);
2159 fval
= _asl_time_string(fmt
, mval
);
2164 asl_string_append_no_encoding(str
, fval
);
2169 asl_string_append_char_no_encoding(str
, '0');
2175 /* Level: num str */
2176 if (!strcmp(key
, ASL_KEY_LEVEL
))
2180 asl_string_append_no_encoding(str
, mval
);
2182 else if (!strcmp(fmt
, "str"))
2184 mval
= _asl_level_string(atoi(mval
));
2185 asl_string_append_no_encoding(str
, mval
);
2189 asl_string_append_no_encoding(str
, mval
);
2195 return asl_string_append(str
, mval
);
2199 * format a message for printing
2200 * out parameter len returns string length including trailing NUL
2203 asl_format_message(asl_msg_t
*msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
2205 char *out
, *vtime
, *k
, c
, skey
[512];
2206 const char *vhost
, *vpid
, *vsender
, *vmessage
, *vlevel
, *vrefproc
, *vrefpid
, *v
, *key
, *val
;
2207 int i
, j
, l
, mf
, paren
, oval
, level
;
2215 if (msg
== NULL
) return NULL
;
2219 if (mfmt
== NULL
) mf
= MFMT_RAW
;
2220 else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf
= MFMT_RAW
;
2221 else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf
= MFMT_STD
;
2222 else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf
= MFMT_BSD
;
2223 else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf
= MFMT_XML
;
2224 else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf
= MFMT_MSG
;
2229 str
= asl_msg_to_string_raw(text_encoding
, msg
, tfmt
);
2230 asl_string_append_char_no_encoding(str
, '\n');
2232 *len
= asl_string_length(str
);
2233 out
= asl_string_free_return_bytes(str
);
2241 if (asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
) != 0) return NULL
;
2243 str
= asl_string_new(text_encoding
);
2244 if (str
== NULL
) return NULL
;
2246 asl_string_append(str
, vmessage
);
2247 asl_string_append_char_no_encoding(str
, '\n');
2249 *len
= asl_string_length(str
);
2250 out
= asl_string_free_return_bytes(str
);
2254 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
2256 /* COMMON: Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/
2257 /* BSD: <COMMON>: message */
2258 /* STD: <COMMON> <Level>: message */
2269 asl_msg_lookup(msg
, ASL_KEY_TIME
, &v
, NULL
);
2270 vtime
= _asl_time_string(tfmt
, v
);
2273 asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &vlevel
, NULL
);
2274 if (vlevel
!= NULL
) level
= atoi(vlevel
);
2276 asl_msg_lookup(msg
, ASL_KEY_HOST
, &vhost
, NULL
);
2277 if (vhost
== NULL
) vhost
= "unknown";
2279 asl_msg_lookup(msg
, ASL_KEY_SENDER
, &vsender
, NULL
);
2280 if (vsender
== NULL
) vsender
= "unknown";
2282 asl_msg_lookup(msg
, ASL_KEY_PID
, &vpid
, NULL
);
2283 asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
);
2284 asl_msg_lookup(msg
, ASL_KEY_REF_PROC
, &vrefproc
, NULL
);
2285 asl_msg_lookup(msg
, ASL_KEY_REF_PID
, &vrefpid
, NULL
);
2288 str
= asl_string_new(text_encoding
);
2289 if (str
== NULL
) return NULL
;
2293 asl_string_append(str
, vtime
);
2298 asl_string_append_char_no_encoding(str
, '0');
2301 asl_string_append_char_no_encoding(str
, ' ');
2302 asl_string_append(str
, vhost
);
2303 asl_string_append_char_no_encoding(str
, ' ');
2304 asl_string_append(str
, vsender
);
2306 if ((vpid
!= NULL
) && (strcmp(vpid
, "-1")))
2308 asl_string_append_char_no_encoding(str
, '[');
2309 asl_string_append(str
, vpid
);
2310 asl_string_append_char_no_encoding(str
, ']');
2313 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_no_encoding(str
, " (");
2315 if (vrefproc
!= NULL
) asl_string_append(str
, vrefproc
);
2316 if (vrefpid
!= NULL
)
2318 asl_string_append_char_no_encoding(str
, '[');
2319 asl_string_append(str
, vrefpid
);
2320 asl_string_append_char_no_encoding(str
, ']');
2323 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_char_no_encoding(str
, ')');
2327 asl_string_append_no_encoding(str
, " <");
2328 asl_string_append(str
, _asl_level_string(level
));
2329 asl_string_append_char_no_encoding(str
, '>');
2332 asl_string_append_no_encoding(str
, ": ");
2333 if (vmessage
!= NULL
) asl_string_append(str
, vmessage
);
2334 asl_string_append_char_no_encoding(str
, '\n');
2336 *len
= asl_string_length(str
);
2337 out
= asl_string_free_return_bytes(str
);
2343 str
= asl_string_new(text_encoding
);
2344 if (str
== NULL
) return NULL
;
2346 asl_string_append_char_no_encoding(str
, '\t');
2347 asl_string_append(str
, "<dict>");
2348 asl_string_append_char_no_encoding(str
, '\n');
2350 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
2352 if (asl_is_utf8(key
) == 1)
2354 asl_string_append_xml_tag(str
, "key", key
);
2355 if (!strcmp(key
, ASL_KEY_TIME
))
2357 vtime
= _asl_time_string(tfmt
, val
);
2360 asl_string_append_xml_tag(str
, "string", vtime
);
2365 asl_string_append_xml_tag(str
, "string", "0");
2370 if (asl_is_utf8(val
) == 1) asl_string_append_xml_tag(str
, "string", val
);
2373 b64
= asl_b64_encode((uint8_t *)val
, strlen(val
));
2374 asl_string_append_xml_tag(str
, "data", (char *)b64
);
2381 asl_string_append_char_no_encoding(str
, '\t');
2382 asl_string_append(str
, "</dict>");
2383 asl_string_append_char_no_encoding(str
, '\n');
2385 *len
= asl_string_length(str
);
2386 out
= asl_string_free_return_bytes(str
);
2392 * The format string may contain arbitrary characters.
2393 * Keys are identified by $Key or $(Key). The value for
2394 * that key is substituted. If there are alterate formats
2395 * for the value (for example a time may be formatted as
2396 * raw seconds, in UTC, or a local timezone), then the
2397 * key may be $((Key)(Format)). "\$" prints a plain "$".
2400 str
= asl_string_new(text_encoding
);
2401 if (str
== NULL
) return NULL
;
2404 * We need enough space to copy any keys found in mfmt.
2405 * The key obviously can't be longer than strlen(mfmt),
2406 * in fact, keys must be shorter, since there's at least a '$'
2407 * in front of the key, so we allocate a buffer with strlen(mfmt).
2408 * If strlen(mfmt) <= sizeof(skey), we use skey to avoid a malloc.
2412 if (x
<= sizeof(skey
))
2419 if (k
== NULL
) return NULL
;
2424 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2430 /* scan key, (key) or ((key)(format)) */
2431 for (j
= i
+ 1; mfmt
[j
] != 0; j
++)
2437 else if (mfmt
[j
] == ')')
2439 if (paren
> 0) paren
--;
2446 else if (((mfmt
[j
] == ' ') || (mfmt
[j
] == '\t')) && (paren
== 0)) break;
2449 /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */
2451 memcpy(k
, mfmt
+i
+1, l
);
2453 _asl_string_append_value_for_key_format(str
, msg
, k
, tfmt
);
2459 if (mfmt
[i
] == '\\')
2462 if (mfmt
[i
] == '$') asl_string_append_char_no_encoding(str
, '$');
2463 else if (mfmt
[i
] == 'e') asl_string_append_char_no_encoding(str
, '\e');
2464 else if (mfmt
[i
] == 's') asl_string_append_char_no_encoding(str
, ' ');
2465 else if (mfmt
[i
] == 'a') asl_string_append_char_no_encoding(str
, '\a');
2466 else if (mfmt
[i
] == 'b') asl_string_append_char_no_encoding(str
, '\b');
2467 else if (mfmt
[i
] == 'f') asl_string_append_char_no_encoding(str
, '\f');
2468 else if (mfmt
[i
] == 'n') asl_string_append_char_no_encoding(str
, '\n');
2469 else if (mfmt
[i
] == 'r') asl_string_append_char_no_encoding(str
, '\r');
2470 else if (mfmt
[i
] == 't') asl_string_append_char_no_encoding(str
, '\t');
2471 else if (mfmt
[i
] == 'v') asl_string_append_char_no_encoding(str
, '\v');
2472 else if (mfmt
[i
] == '\'') asl_string_append_char_no_encoding(str
, '\'');
2473 else if (mfmt
[i
] == '\\') asl_string_append_char_no_encoding(str
, '\\');
2474 else if (isdigit(mfmt
[i
]))
2476 oval
= mfmt
[i
] - '0';
2477 if (isdigit(mfmt
[i
+1]))
2480 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2481 if (isdigit(mfmt
[i
+1]))
2484 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2488 asl_string_append_char_no_encoding(str
, c
);
2493 if (mfmt
[i
] == '\0') break;
2494 asl_string_append_char_no_encoding(str
, mfmt
[i
]);
2497 if (k
!= skey
) free(k
);
2499 asl_string_append_char_no_encoding(str
, '\n');
2501 *len
= asl_string_length(str
);
2502 out
= asl_string_free_return_bytes(str
);
2507 * OLD ASLMSG COMPATIBILITY
2510 asl_key(aslmsg msg
, uint32_t n
)
2516 for (page
= (asl_msg_t
*)msg
; page
!= NULL
; page
= page
->next
)
2518 for (slot
= 0; slot
< ASL_MSG_PAGE_SLOTS
; slot
++)
2520 if (page
->key
[slot
] != ASL_MSG_SLOT_FREE
)
2522 if (i
== n
) return _asl_msg_slot_key(page
, slot
);
2532 asl_new(uint32_t type
)
2534 return (aslmsg
)asl_msg_new(type
);
2538 asl_set(aslmsg msg
, const char *key
, const char *value
)
2540 return asl_msg_set_key_val_op((asl_msg_t
*)msg
, key
, value
, IndexNull
);
2544 asl_set_query(aslmsg msg
, const char *key
, const char *value
, uint32_t op
)
2546 return asl_msg_set_key_val_op((asl_msg_t
*)msg
, key
, value
, op
);
2550 asl_unset(aslmsg msg
, const char *key
)
2552 asl_msg_unset((asl_msg_t
*)msg
, key
);
2557 asl_get(aslmsg msg
, const char *key
)
2563 status
= asl_msg_lookup((asl_msg_t
*)msg
, key
, &val
, NULL
);
2564 if (status
!= 0) return NULL
;
2569 asl_free(aslmsg msg
)
2571 asl_msg_release((asl_msg_t
*)msg
);
2577 * aslresponse_next: Iterate over responses returned from asl_search()
2578 * a: a response returned from asl_search();
2579 * returns: The next log message (an aslmsg) or NULL on failure
2582 aslresponse_next(aslresponse r
)
2584 asl_search_result_t
*res
;
2587 res
= (asl_search_result_t
*)r
;
2588 if (res
== NULL
) return NULL
;
2590 if (res
->curr
>= res
->count
) return NULL
;
2591 m
= res
->msg
[res
->curr
];
2598 * aslresponse_free: Free a response returned from asl_search()
2599 * a: a response returned from asl_search()
2602 aslresponse_free(aslresponse r
)
2604 asl_search_result_t
*res
;
2607 res
= (asl_search_result_t
*)r
;
2608 if (res
== NULL
) return;
2610 for (i
= 0; i
< res
->count
; i
++) asl_msg_release(res
->msg
[i
]);