]> git.saurik.com Git - apple/libc.git/blob - gen/asl_msg.c
Libc-825.25.tar.gz
[apple/libc.git] / gen / asl_msg.c
1 /*
2 * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <string.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <regex.h>
32 #include <syslog.h>
33 #include <errno.h>
34 #include <time.h>
35 #include <sys/time.h>
36 #include <asl.h>
37 #include <asl_private.h>
38 #include <asl_core.h>
39 #include <sys/types.h>
40 #include <libkern/OSAtomic.h>
41 #include <assert.h>
42 #include "asl_msg.h"
43
44 #define TOKEN_NULL 0
45 #define TOKEN_OPEN 1
46 #define TOKEN_CLOSE 2
47 #define TOKEN_WORD 3
48 #define TOKEN_INT 4
49
50 #define MFMT_RAW 0
51 #define MFMT_STD 1
52 #define MFMT_BSD 2
53 #define MFMT_XML 3
54 #define MFMT_STR 4
55 #define MFMT_MSG 5
56
57 #define SEC_PER_HOUR 3600
58
59 #define forever for(;;)
60
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)
66
67 #ifndef ASL_KEY_OPTION
68 #define ASL_KEY_OPTION "ASLOption"
69 #endif
70
71 #ifndef ASL_QUERY_OP_FALSE
72 #define ASL_QUERY_OP_FALSE 0
73 #endif
74
75 #define AUX_0_TIME 0x00000001
76 #define AUX_0_TIME_NSEC 0x00000002
77 #define AUX_0_HOST 0x00000004
78 #define AUX_0_SENDER 0x00000008
79 #define AUX_0_FACILITY 0x00000010
80 #define AUX_0_PID 0x00000020
81 #define AUX_0_UID 0x00000040
82 #define AUX_0_GID 0x00000080
83 #define AUX_0_MSG 0x00000100
84 #define AUX_0_OPTION 0x00000200
85 #define AUX_0_LEVEL 0x00000400
86
87 extern time_t asl_parse_time(const char *in);
88
89 /* from asl_util.c */
90 int asl_is_utf8(const char *str);
91 uint8_t *asl_b64_encode(const uint8_t *buf, size_t len);
92
93 static const char *ASLStandardKey[] =
94 {
95 ASL_KEY_TIME,
96 ASL_KEY_TIME_NSEC,
97 ASL_KEY_HOST,
98 ASL_KEY_SENDER,
99 ASL_KEY_FACILITY,
100 ASL_KEY_PID,
101 ASL_KEY_UID,
102 ASL_KEY_GID,
103 ASL_KEY_LEVEL,
104 ASL_KEY_MSG,
105 ASL_KEY_READ_UID,
106 ASL_KEY_READ_GID,
107 ASL_KEY_SESSION,
108 ASL_KEY_REF_PID,
109 ASL_KEY_REF_PROC,
110 ASL_KEY_MSG_ID,
111 ASL_KEY_EXPIRE_TIME,
112 ASL_KEY_OPTION
113 };
114
115 static const char *MTStandardKey[] =
116 {
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"
130 };
131
132 static uint16_t
133 _asl_msg_std_key(const char *s, uint32_t len)
134 {
135 if ((len > 18) && (streq_len(s, "com.apple.message.", 18)))
136 {
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;
150
151 return 0;
152 }
153
154 switch (len)
155 {
156 case 3:
157 {
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;
161 }
162 case 4:
163 {
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;
166 }
167 case 5:
168 {
169 if streq(s, ASL_KEY_LEVEL) return ASL_STD_KEY_LEVEL;
170 }
171 case 6:
172 {
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;
175 }
176 case 7:
177 {
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;
183 }
184 case 8:
185 {
186 if streq(s, ASL_KEY_FACILITY) return ASL_STD_KEY_FACILITY;
187 }
188 case 9:
189 {
190 if streq(s, ASL_KEY_OPTION) return ASL_STD_KEY_OPTION;
191 }
192 case 11:
193 {
194 if streq(s, ASL_KEY_TIME_NSEC) return ASL_STD_KEY_NANO;
195 }
196 case 12:
197 {
198 if streq(s, ASL_KEY_MSG_ID) return ASL_STD_KEY_MSG_ID;
199 }
200 case 13:
201 {
202 if streq(s, ASL_KEY_EXPIRE_TIME) return ASL_STD_KEY_EXPIRE;
203 }
204 default:
205 {
206 return 0;
207 }
208 }
209
210 return 0;
211 }
212
213 static asl_msg_t *
214 _asl_msg_make_page()
215 {
216 asl_msg_t *out;
217 int i;
218
219 out = calloc(1, sizeof(asl_msg_t));
220 if (out == NULL) return NULL;
221
222 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
223 {
224 out->key[i] = ASL_MSG_SLOT_FREE;
225 out->val[i] = ASL_MSG_SLOT_FREE;
226 }
227
228 return out;
229 }
230
231 static const char *
232 _asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
233 {
234 const char *out;
235 uint16_t x;
236
237 if (page == NULL) return NULL;
238 if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
239
240 if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL;
241
242 switch (page->key[slot] & ASL_MSG_KV_MASK)
243 {
244 case ASL_MSG_KV_INLINE:
245 {
246 return page->data + page->key[slot];
247 }
248 case ASL_MSG_KV_DICT:
249 {
250 if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST))
251 {
252 x = page->key[slot] - ASL_STD_KEY_BASE - 1;
253 return ASLStandardKey[x];
254 }
255 else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST))
256 {
257 x = page->key[slot] - ASL_MT_KEY_BASE - 1;
258 return MTStandardKey[x];
259 }
260
261 return NULL;
262 }
263 case ASL_MSG_KV_EXTERN:
264 {
265 x = page->key[slot] & ASL_MSG_OFFSET_MASK;
266 memcpy(&out, page->data + x, sizeof(char *));
267 return out;
268 }
269 }
270
271 return NULL;
272 }
273
274 static const char *
275 _asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
276 {
277 const char *out;
278 uint16_t x, type;
279
280 if (page == NULL) return NULL;
281 if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
282
283 if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL;
284
285 type = page->val[slot] & ASL_MSG_KV_MASK;
286
287 if (type == ASL_MSG_KV_INLINE)
288 {
289 return page->data + page->val[slot];
290 }
291 else if (type == ASL_MSG_KV_EXTERN)
292 {
293 x = page->val[slot] & ASL_MSG_OFFSET_MASK;
294 memcpy(&out, page->data + x, sizeof(char *));
295 return out;
296 }
297
298 return NULL;
299 }
300
301 /*
302 * asl_new: create a new log message.
303 */
304 asl_msg_t *
305 asl_msg_new(uint32_t type)
306 {
307 asl_msg_t *out;
308
309 out = _asl_msg_make_page();
310 if (out == NULL) return NULL;
311
312 out->type = type;
313 out->refcount = 1;
314
315 return out;
316 }
317
318 asl_msg_t *
319 asl_msg_retain(asl_msg_t *msg)
320 {
321 int32_t new;
322
323 if (msg == NULL) return NULL;
324
325 new = OSAtomicIncrement32Barrier(&msg->refcount);
326 assert(new >= 1);
327
328 return msg;
329 }
330
331 static void
332 _asl_msg_free(asl_msg_t *page)
333 {
334 uint32_t i;
335 char *p;
336
337 if (page == NULL) return;
338
339 for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
340 {
341 if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
342 {
343 memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
344 free(p);
345 }
346
347 if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
348 {
349 memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
350 free(p);
351 }
352 }
353
354 free(page);
355 }
356
357 void
358 asl_msg_release(asl_msg_t *msg)
359 {
360 int32_t new;
361 asl_msg_t *next;
362
363 if (msg == NULL) return;
364
365 new = OSAtomicDecrement32Barrier(&msg->refcount);
366 assert(new >= 0);
367
368 if (new > 0) return;
369
370 while (msg != NULL)
371 {
372 next = msg->next;
373 _asl_msg_free(msg);
374 msg = next;
375 }
376 }
377
378 static uint32_t
379 _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
380 {
381 uint32_t i, len, slot;
382 uint16_t kx;
383 asl_msg_t *page;
384 const char *kp;
385
386 if (msg == NULL) return IndexNull;
387 if (key == NULL) return IndexNull;
388
389 i = 0;
390 slot = 0;
391 if (oslot != NULL) *oslot = slot;
392
393 page = msg;
394 if (opage != NULL) *opage = page;
395
396 len = strlen(key);
397 kx = _asl_msg_std_key(key, len);
398
399 forever
400 {
401 if (page->key[slot] != ASL_MSG_SLOT_FREE)
402 {
403 if (kx != 0)
404 {
405 if (page->key[slot] == kx) return i;
406 }
407 else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
408 {
409 /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
410 }
411 else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
412 {
413 memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
414 if (streq(key, kp)) return i;
415 }
416 else
417 {
418 kp = page->data + page->key[slot];
419 if (streq(key, kp)) return i;
420 }
421 }
422
423 i++;
424 slot++;
425 if (oslot != NULL) *oslot = slot;
426
427 if (slot >= ASL_MSG_PAGE_SLOTS)
428 {
429 if (page->next == NULL) return IndexNull;
430
431 slot = 0;
432 if (oslot != NULL) *oslot = slot;
433
434 page = page->next;
435 if (opage != NULL) *opage = page;
436 }
437 }
438
439 return IndexNull;
440 }
441
442 /*
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
448 */
449 static uint32_t
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)
451 {
452 uint32_t slot;
453 asl_msg_t *page;
454
455 if (msg == NULL) return IndexNull;
456 if (outpage != NULL) *outpage = NULL;
457 if (outslot != NULL) *outslot = IndexNull;
458
459 slot = n;
460 page = msg;
461
462 while (slot >= ASL_MSG_PAGE_SLOTS)
463 {
464 if (page->next == NULL) return IndexNull;
465 page = page->next;
466 slot -= ASL_MSG_PAGE_SLOTS;
467 }
468
469 while (page->key[slot] == ASL_MSG_SLOT_FREE)
470 {
471 slot++;
472 n++;
473
474 if (slot >= ASL_MSG_PAGE_SLOTS)
475 {
476 if (page->next == NULL) return IndexNull;
477 page = page->next;
478 slot = 0;
479 }
480 }
481
482 n++;
483
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];
487
488 if (outpage != NULL) *outpage = page;
489 if (outslot != NULL) *outslot = slot;
490
491 return n;
492 }
493
494 uint32_t
495 asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout)
496 {
497 return _asl_msg_fetch_internal(msg, n, keyout, valout, opout, NULL, NULL);
498 }
499
500 static int
501 _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
502 {
503 uint32_t slot, keylen, vallen, total;
504 uint16_t kx;
505 asl_msg_t *page, *last;
506 char *extkey, *extval;
507
508 if (msg == NULL) return -1;
509 if (key == NULL) return -1;
510
511 extkey = NULL;
512 extval = NULL;
513
514 keylen = strlen(key);
515 kx = _asl_msg_std_key(key, keylen);
516
517 if (kx == 0) keylen++;
518 else keylen = 0;
519
520 total = keylen;
521
522 vallen = 0;
523 if (val != NULL)
524 {
525 vallen = strlen(val) + 1;
526 total += vallen;
527 }
528
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)
531 {
532 extkey = strdup(key);
533 keylen = sizeof(char *);
534 }
535
536 if (vallen > ASL_MSG_PAGE_DATA_SIZE)
537 {
538 extval = strdup(val);
539 vallen = sizeof(char *);
540 }
541
542 total = keylen + vallen;
543 if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extval == NULL) && (keylen > 0))
544 {
545 extval = strdup(val);
546 vallen = sizeof(char *);
547 total = keylen + vallen;
548 }
549
550 if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extkey == NULL))
551 {
552 extkey = strdup(key);
553 keylen = sizeof(char *);
554 total = keylen + vallen;
555 }
556
557 if (total > ASL_MSG_PAGE_DATA_SIZE)
558 {
559 /* can't happen, but... */
560 if (extkey != NULL) free(extkey);
561 if (extval != NULL) free(extval);
562 return -1;
563 }
564
565 /* find a page with space for the key and value and a free slot*/
566 slot = 0;
567 last = msg;
568
569 for (page = msg; page != NULL; page = page->next)
570 {
571 last = page;
572
573 if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
574 {
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;
578 }
579 }
580
581 if (page == NULL)
582 {
583 /* allocate a new page and attach it */
584 page = _asl_msg_make_page();
585 if (page == NULL)
586 {
587 if (extkey != NULL) free(extkey);
588 if (extval != NULL) free(extval);
589 return -1;
590 }
591
592 last->next = page;
593 slot = 0;
594 }
595
596 /* copy key or external key pointer into page data */
597 if (kx != 0)
598 {
599 page->key[slot] = kx;
600 }
601 else if (extkey == NULL)
602 {
603 page->key[slot] = page->data_size;
604 memcpy(page->data + page->data_size, key, keylen);
605 }
606 else
607 {
608 page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN;
609 memcpy(page->data + page->data_size, &extkey, keylen);
610 }
611
612 page->data_size += keylen;
613
614 /* copy val or external val pointer into page data */
615 page->val[slot] = ASL_MSG_SLOT_FREE;
616
617 if (val != NULL)
618 {
619 if (extval == NULL)
620 {
621 page->val[slot] = page->data_size;
622 memcpy(page->data + page->data_size, val, vallen);
623 }
624 else
625 {
626 page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN;
627 memcpy(page->data + page->data_size, &extval, vallen);
628 }
629
630 page->data_size += vallen;
631 }
632
633 /* set op */
634 page->op[slot] = op;
635
636 /* update page count */
637 page->count++;
638
639 return 0;
640 }
641
642 /*
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.
646 *
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.
649 */
650 static int
651 _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
652 {
653 uint32_t i, slot, newexternal;
654 asl_msg_t *page;
655 uint32_t intvallen, extvallen, newvallen;
656 char *intval, *extval, *newval;
657
658 if (msg == NULL) return -1;
659 if (key == NULL) return -1;
660
661 slot = IndexNull;
662 page = NULL;
663
664 if ((msg->type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
665 {
666 /* add key */
667 return _asl_msg_new_key_val_op(msg, key, val, op);
668 }
669
670 intval = NULL;
671 intvallen = 0;
672
673 extval = NULL;
674 extvallen = 0;
675
676 if (page->val[slot] != ASL_MSG_SLOT_FREE)
677 {
678 if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
679 {
680 i = page->val[slot] & ASL_MSG_OFFSET_MASK;
681 memcpy(&extval, page->data + i, sizeof(char *));
682 extvallen = sizeof(char *);
683 }
684 else
685 {
686 intval = page->data + page->val[slot];
687 intvallen = strlen(intval) + 1;
688 }
689 }
690
691 /* replace val and op for existing entry */
692
693 /* easy case - remove val */
694 if (val == NULL)
695 {
696 if (extval != NULL) free(extval);
697 page->val[slot] = ASL_MSG_SLOT_FREE;
698 if (op != IndexNull) page->op[slot] = op;
699 return 0;
700 }
701
702 /* trivial case - internal val doesn't change */
703 if ((intval != NULL) && (streq(val, intval)))
704 {
705 if (op != IndexNull) page->op[slot] = op;
706 return 0;
707 }
708
709 /* trivial case - external val doesn't change */
710 if ((extval != NULL) && (streq(val, extval)))
711 {
712 if (op != IndexNull) page->op[slot] = op;
713 return 0;
714 }
715
716 /*
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]
720 */
721 i = page->val[slot] & ASL_MSG_OFFSET_MASK;
722 if ((intval != NULL) && ((i + intvallen) == page->data_size))
723 {
724 page->val[slot] = ASL_MSG_SLOT_FREE;
725 page->data_size -= intvallen;
726 intval = NULL;
727 intvallen = 0;
728 }
729 else if ((extval != NULL) && ((i + extvallen) == page->data_size))
730 {
731 page->val[slot] = ASL_MSG_SLOT_FREE;
732 page->data_size -= extvallen;
733 free(extval);
734 extval = NULL;
735 extvallen = 0;
736 }
737
738 /* val changes - see if it needs to be external */
739 newvallen = strlen(val) + 1;
740 newexternal = 0;
741
742 if (newvallen > ASL_MSG_PAGE_DATA_SIZE)
743 {
744 newexternal = 1;
745 newvallen = sizeof(char *);
746 }
747
748 /* check if there is room to change val in place */
749 if (((extval != NULL) && (newvallen <= extvallen)) || ((extval == NULL) && (newvallen <= intvallen)))
750 {
751 if (extval != NULL) free(extval);
752 extval = NULL;
753
754 /* we can re-use the space of the old value */
755 i = page->val[slot] & ASL_MSG_OFFSET_MASK;
756
757 if (newexternal == 1)
758 {
759 /* create an external val and copy in the new pointer */
760 newval = strdup(val);
761 if (newval == NULL) return -1;
762
763 page->val[slot] = i | ASL_MSG_KV_EXTERN;
764 memcpy(page->data + i, &newval, sizeof(char *));
765 }
766 else
767 {
768 /* new internal value */
769 page->val[slot] = i;
770 memcpy(page->data + i, val, newvallen);
771 }
772
773 if (op != IndexNull) page->op[slot] = op;
774 return 0;
775 }
776
777 /* we're done with the old value if it is external - free it now */
778 if (extval != NULL) free(extval);
779 extval = NULL;
780
781 if (newvallen <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
782 {
783 /* can't re-use the old space, but there's room on the page */
784 i = page->data_size;
785 page->data_size += newvallen;
786
787 if (newexternal == 1)
788 {
789 /* create an external val and copy in the new pointer */
790 newval = strdup(val);
791 if (newval == NULL) return -1;
792
793 page->val[slot] = i | ASL_MSG_KV_EXTERN;
794 memcpy(page->data + i, &newval, sizeof(char *));
795 }
796 else
797 {
798 /* new internal value */
799 page->val[slot] = i;
800 memcpy(page->data + i, val, newvallen);
801 }
802
803 if (op != IndexNull) page->op[slot] = op;
804 return 0;
805
806 }
807
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)
810 {
811 memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
812 free(extval);
813 }
814
815 page->key[slot] = ASL_MSG_SLOT_FREE;
816 page->val[slot] = ASL_MSG_SLOT_FREE;
817 page->op[slot] = 0;
818
819 return _asl_msg_new_key_val_op(msg, key, val, op);
820 }
821
822 int
823 asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
824 {
825 char *special, buf[512];
826 uint32_t i, len;
827 int status;
828
829 /* Special case handling */
830 special = NULL;
831
832 /* convert "Level" values to "0" through "7" */
833 if (streq(key, ASL_KEY_LEVEL))
834 {
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";
845 else val = "7";
846 }
847
848 /* strip trailing newlines from "Message" values */
849 if ((streq(key, ASL_KEY_MSG)) && (val != NULL))
850 {
851 len = strlen(val);
852 i = len;
853 while ((i > 0) && (val[i - 1] == '\n')) i--;
854 if (i == 0) val = NULL;
855 else if (i < len)
856 {
857 /* use buf if it is big enough, else malloc a temporary buffer */
858 if (i < sizeof(buf))
859 {
860 memcpy(buf, val, i);
861 buf[i] = 0;
862 val = (const char *)buf;
863 }
864 else
865 {
866 special = malloc(i + 1);
867 if (special == NULL) return -1;
868 memcpy(special, val, i);
869 special[i] = 0;
870 val = (const char *)special;
871 }
872 }
873 }
874
875 status = _asl_msg_set_kvo(msg, key, val, op);
876
877 if (special != NULL) free(special);
878 return status;
879 }
880
881 int
882 asl_msg_set_key_val(asl_msg_t *msg, const char *key, const char *val)
883 {
884 return asl_msg_set_key_val_op(msg, key, val, 0);
885 }
886
887 /*
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.
891 */
892 static void
893 _asl_msg_merge_key_val(asl_msg_t *msg, const char *key, const char *val)
894 {
895 uint32_t i, slot;
896 asl_msg_t *page;
897
898 if (msg == NULL) return;
899 if (key == NULL) return;
900
901 slot = IndexNull;
902 page = NULL;
903
904 i = _asl_msg_index(msg, key, &slot, &page);
905 if (i != IndexNull) return;
906
907 asl_msg_set_key_val_op(msg, key, val, 0);
908 }
909
910 /*
911 * Merge msg into target (does not replace existing keys).
912 * Creates a new asl_msg_t if target is NULL.
913 * Returns target.
914 */
915 asl_msg_t *
916 asl_msg_merge(asl_msg_t *target, asl_msg_t *msg)
917 {
918 uint32_t x, slot, op, isnew = 0;
919 const char *key, *val;
920 asl_msg_t *page;
921
922 if (msg == NULL) return target;
923
924 if (target == NULL)
925 {
926 isnew = 1;
927 target = asl_msg_new(ASL_TYPE_MSG);
928 }
929
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))
931 {
932 if (isnew == 1) asl_msg_set_key_val_op(target, key, val, 0);
933 else _asl_msg_merge_key_val(target, key, val);
934 }
935
936 return target;
937 }
938
939 /*
940 * Copy msg.
941 */
942 asl_msg_t *
943 asl_msg_copy(asl_msg_t *msg)
944 {
945 return asl_msg_merge(NULL, msg);
946 }
947
948 /*
949 * asl_msg_unset
950 * Frees external key and val strings, but does not try to reclaim data space.
951 */
952 void
953 asl_msg_unset(asl_msg_t *msg, const char *key)
954 {
955 uint32_t i, slot;
956 asl_msg_t *page;
957 char *ext;
958
959 if (msg == NULL) return;
960 if (key == NULL) return;
961
962 slot = IndexNull;
963 page = NULL;
964
965 i = _asl_msg_index(msg, key, &slot, &page);
966 if (i == IndexNull) return;
967
968 if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
969 {
970 memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
971 free(ext);
972 }
973
974 if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
975 {
976 memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
977 free(ext);
978 }
979
980 page->key[slot] = ASL_MSG_SLOT_FREE;
981 page->val[slot] = ASL_MSG_SLOT_FREE;
982 page->op[slot] = 0;
983
984 page->count--;
985 }
986
987 int
988 asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint32_t *opout)
989 {
990 uint32_t i, slot;
991 asl_msg_t *page;
992
993 slot = IndexNull;
994 page = NULL;
995
996 i = _asl_msg_index(msg, key, &slot, &page);
997 if (i == IndexNull) return -1;
998
999 if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
1000 if (opout != NULL) *opout = page->op[slot];
1001
1002 return 0;
1003 }
1004
1005 uint32_t
1006 asl_msg_type(asl_msg_t *msg)
1007 {
1008 if (msg == NULL) return 0;
1009 return msg->type;
1010 }
1011
1012 uint32_t
1013 asl_msg_count(asl_msg_t *msg)
1014 {
1015 uint32_t total;
1016
1017 total = 0;
1018
1019 for (; msg != NULL; msg = msg->next) total += msg->count;
1020 return total;
1021 }
1022
1023 /*
1024 * Compare messages
1025 */
1026 static int
1027 _asl_msg_equal(asl_msg_t *a, asl_msg_t *b)
1028 {
1029 uint32_t x, oa, ob;
1030 const char *key, *va, *vb;
1031
1032 if (asl_msg_count(a) != asl_msg_count(b)) return 0;
1033
1034 key = NULL;
1035 va = NULL;
1036 oa = 0;
1037
1038
1039 for (x = asl_msg_fetch(a, 0, &key, &va, &oa); x != IndexNull; x = asl_msg_fetch(a, x, &key, &va, &oa))
1040 {
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;
1044 }
1045
1046 return 1;
1047 }
1048
1049 static int
1050 _asl_isanumber(const char *s)
1051 {
1052 int i;
1053
1054 if (s == NULL) return 0;
1055
1056 i = 0;
1057 if ((s[0] == '-') || (s[0] == '+')) i = 1;
1058
1059 if (s[i] == '\0') return 0;
1060
1061 for (; s[i] != '\0'; i++)
1062 {
1063 if (!isdigit(s[i])) return 0;
1064 }
1065
1066 return 1;
1067 }
1068
1069 static int
1070 _asl_msg_basic_test(uint32_t op, const char *q, const char *m, uint32_t n)
1071 {
1072 int cmp;
1073 uint32_t t;
1074 int64_t nq, nm;
1075 int rflags;
1076 regex_t rex;
1077
1078 t = op & ASL_QUERY_OP_TRUE;
1079
1080 /* NULL value from query or message string fails */
1081 if ((q == NULL) || (m == NULL)) return (t & ASL_QUERY_OP_NOT_EQUAL);
1082
1083 if (op & ASL_QUERY_OP_REGEX)
1084 {
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;
1087
1088 memset(&rex, 0, sizeof(regex_t));
1089
1090 rflags = REG_EXTENDED | REG_NOSUB;
1091 if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE;
1092
1093 /* A bad reqular expression matches nothing */
1094 if (regcomp(&rex, q, rflags) != 0) return (t & ASL_QUERY_OP_NOT_EQUAL);
1095
1096 cmp = regexec(&rex, m, 0, NULL, 0);
1097 regfree(&rex);
1098
1099 if (t == ASL_QUERY_OP_NOT_EQUAL) return (cmp != 0);
1100 return (cmp == 0);
1101 }
1102
1103 if (op & ASL_QUERY_OP_NUMERIC)
1104 {
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);
1107
1108 nq = atoll(q);
1109 nm = atoll(m);
1110
1111 switch (t)
1112 {
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);
1120 }
1121 }
1122
1123 cmp = 0;
1124 if (op & ASL_QUERY_OP_CASEFOLD)
1125 {
1126 if (n == 0) cmp = strcasecmp(m, q);
1127 else cmp = strncasecmp(m, q, n);
1128 }
1129 else
1130 {
1131 if (n == 0) cmp = strcmp(m, q);
1132 else cmp = strncmp(m, q, n);
1133 }
1134
1135 switch (t)
1136 {
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);
1143 }
1144
1145 return (t == ASL_QUERY_OP_NOT_EQUAL);
1146 }
1147
1148 static int
1149 _asl_msg_test_substring(uint32_t op, const char *q, const char *m)
1150 {
1151 uint32_t t, i, d, lm, lq, match, newop;
1152
1153 t = op & ASL_QUERY_OP_TRUE;
1154
1155 lm = 0;
1156 if (m != NULL) lm = strlen(m);
1157
1158 lq = 0;
1159 if (q != NULL) lq = strlen(q);
1160
1161 /* NULL is a substring of any string */
1162 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
1163
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);
1166
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;
1169
1170 /*
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.
1174 */
1175 newop = op & 0xff0;
1176 newop |= ASL_QUERY_OP_EQUAL;
1177
1178 match = 0;
1179 d = lm - lq;
1180 for (i = 0; i <= d; i++)
1181 {
1182 if (_asl_msg_basic_test(newop, q, m + i, lq) != 0)
1183 {
1184 if (t & ASL_QUERY_OP_EQUAL) return 1;
1185 match++;
1186 }
1187 }
1188
1189 /* If the input test was for equality, no matches were found */
1190 if (t & ASL_QUERY_OP_EQUAL) return 0;
1191
1192 /* The input test was for not equal. Return true if no matches were found */
1193 return (match == 0);
1194 }
1195
1196 static int
1197 _asl_msg_test_prefix(uint32_t op, const char *q, const char *m)
1198 {
1199 uint32_t lm, lq, t;
1200
1201 t = op & ASL_QUERY_OP_TRUE;
1202
1203 lm = 0;
1204 if (m != NULL) lm = strlen(m);
1205
1206 lq = 0;
1207 if (q != NULL) lq = strlen(q);
1208
1209 /* NULL is a prefix of any string */
1210 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
1211
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);
1214
1215 /* Compare two equal-length strings */
1216 return _asl_msg_basic_test(op, q, m, lq);
1217 }
1218
1219 static int
1220 _asl_msg_test_suffix(uint32_t op, const char *q, const char *m)
1221 {
1222 uint32_t lm, lq, d, t;
1223
1224 t = op & ASL_QUERY_OP_TRUE;
1225
1226 lm = 0;
1227 if (m != NULL) lm = strlen(m);
1228
1229 lq = 0;
1230 if (q != NULL) lq = strlen(q);
1231
1232 /* NULL is a suffix of any string */
1233 if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
1234
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);
1237
1238 /* Compare two equal-length strings */
1239 d = lm - lq;
1240 return _asl_msg_basic_test(op, q, m + d, lq);
1241 }
1242
1243 /*
1244 * Splits out prefix, suffix, and substring tests.
1245 * Sends the rest to _asl_msg_basic_test().
1246 */
1247 static int
1248 _asl_msg_test_expression(uint32_t op, const char *q, const char *m)
1249 {
1250 uint32_t t;
1251
1252 t = op & ASL_QUERY_OP_TRUE;
1253 if (t == ASL_QUERY_OP_TRUE) return 1;
1254
1255 if (op & ASL_QUERY_OP_PREFIX)
1256 {
1257 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_substring(op, q, m);
1258 return _asl_msg_test_prefix(op, q, m);
1259 }
1260 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_suffix(op, q, m);
1261
1262 return _asl_msg_basic_test(op, q, m, 0);
1263 }
1264
1265 /*
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.
1269 */
1270 static int
1271 _asl_msg_test_time_expression(uint32_t op, const char *q, const char *m)
1272 {
1273 time_t tq, tm;
1274 uint32_t t;
1275
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);
1278
1279 tq = asl_parse_time(q);
1280 if (tq < 0) return _asl_msg_test_expression(op, q, m);
1281
1282 tm = asl_parse_time(m);
1283 if (tm < 0) return _asl_msg_test_expression(op, q, m);
1284
1285 t = op & ASL_QUERY_OP_TRUE;
1286
1287 switch (t)
1288 {
1289 case ASL_QUERY_OP_FALSE:
1290 {
1291 return 0;
1292 }
1293 case ASL_QUERY_OP_EQUAL:
1294 {
1295 if (tm == tq) return 1;
1296 return 0;
1297 }
1298 case ASL_QUERY_OP_GREATER:
1299 {
1300 if (tm > tq) return 1;
1301 return 0;
1302 }
1303 case ASL_QUERY_OP_GREATER_EQUAL:
1304 {
1305 if (tm >= tq) return 1;
1306 return 0;
1307 }
1308 case ASL_QUERY_OP_LESS:
1309 {
1310 if (tm < tq) return 1;
1311 return 0;
1312 }
1313 case ASL_QUERY_OP_LESS_EQUAL:
1314 {
1315 if (tm <= tq) return 1;
1316 return 0;
1317 }
1318 case ASL_QUERY_OP_NOT_EQUAL:
1319 {
1320 if (tm != tq) return 1;
1321 return 0;
1322 }
1323 case ASL_QUERY_OP_TRUE:
1324 {
1325 return 1;
1326 }
1327 }
1328
1329 /* NOTREACHED */
1330 return 0;
1331 }
1332
1333 /* test a query against a message */
1334 static int
1335 _asl_msg_test(asl_msg_t *q, asl_msg_t *m)
1336 {
1337 uint32_t i, t, x, op;
1338 int cmp;
1339 const char *kq, *vq, *vm;
1340
1341 /*
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).
1345 */
1346
1347 kq = NULL;
1348 vq = NULL;
1349 op = 0;
1350
1351 for (x = asl_msg_fetch(q, 0, &kq, &vq, &op); x != IndexNull; x = asl_msg_fetch(q, x, &kq, &vq, &op))
1352 {
1353 /* Find query key in the message */
1354 vm = NULL;
1355 i = asl_msg_lookup(m, kq, &vm, NULL);
1356
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)
1360 {
1361 if (i != 0) return 0;
1362 continue;
1363 }
1364
1365 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1366 if (t == ASL_QUERY_OP_FALSE)
1367 {
1368 if (i == 0) return 0;
1369 continue;
1370 }
1371
1372 if (i != 0)
1373 {
1374 /* the message does NOT have query key - fail unless we are testing not equal */
1375 if (t == ASL_QUERY_OP_NOT_EQUAL) continue;
1376 return 0;
1377 }
1378
1379 cmp = 1;
1380 if (streq(kq, ASL_KEY_TIME))
1381 {
1382 cmp = _asl_msg_test_time_expression(op, vq, vm);
1383 }
1384 else
1385 {
1386 cmp = _asl_msg_test_expression(op, vq, vm);
1387 }
1388
1389 if (cmp == 0) return 0;
1390 }
1391
1392 return 1;
1393 }
1394
1395 int
1396 asl_msg_cmp(asl_msg_t *a, asl_msg_t *b)
1397 {
1398
1399 if (a == NULL) return 0;
1400 if (b == NULL) return 0;
1401
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);
1405 }
1406
1407
1408 static char *
1409 _asl_time_string(const char *fmt, const char *str)
1410 {
1411 time_t tick, off;
1412 struct tm stm;
1413 char *ltime;
1414 char *out;
1415 char ltbuf[32];
1416 out = NULL;
1417 time_t min;
1418 const char *p = fmt;
1419
1420 tick = 0;
1421 if (str != NULL) tick = asl_parse_time(str);
1422
1423 /* default format is local time zone */
1424 if ((fmt == NULL) || (!strcasecmp(fmt, "lcl")) || (!strcasecmp(fmt, "local")))
1425 {
1426 ltime = ctime_r(&tick, ltbuf);
1427 if (ltime == NULL) return NULL;
1428 ltime[19] = '\0';
1429 asprintf(&out, "%s", ltime + 4);
1430 return out;
1431 }
1432
1433 if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
1434 {
1435 asprintf(&out, "%lu", tick);
1436 return out;
1437 }
1438
1439 if (!strcasecmp(fmt, "j"))
1440 {
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);
1443 return out;
1444 }
1445
1446 if ((!strcasecmp(fmt, "utc")) || (!strcasecmp(fmt, "zulu")))
1447 {
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);
1450 return out;
1451 }
1452
1453 if ((fmt[1] == '\0') && (((fmt[0] >= 'a') && (fmt[0] <= 'z')) || ((fmt[0] >= 'A') && (fmt[0] <= 'Z'))))
1454 {
1455 char z = fmt[0];
1456 if (z >= 'a') z -= 32;
1457
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;
1462 else return NULL;
1463 }
1464 else
1465 {
1466 if ((*p == '-') || (*p == '+')) p++;
1467 if ((*p) >= '0' && (*p <= '9'))
1468 {
1469 off = atoi(p);
1470 if (fmt[0] == '-') off *= -1;
1471 off *= SEC_PER_HOUR;
1472
1473 p = strchr(p, ':');
1474 if (p != NULL)
1475 {
1476 min = atoi(p + 1);
1477 if (fmt[0] == '-') min *= -1;
1478 min *= 60;
1479 off += min;
1480 }
1481 }
1482 else
1483 {
1484 return NULL;
1485 }
1486 }
1487
1488 tick += off;
1489
1490 memset(&stm, 0, sizeof (struct tm));
1491 if (NULL == gmtime_r(&tick, &stm)) return NULL;
1492
1493 if ((fmt[0] >= 'A') && (fmt[0] <= 'Z'))
1494 {
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]);
1496 }
1497 else if ((fmt[0] >= 'a') && (fmt[0] <= 'z'))
1498 {
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);
1500 }
1501 else if ((fmt[0] >= '0') && (fmt[0] <= '9'))
1502 {
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);
1504 }
1505 else
1506 {
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);
1508 }
1509
1510 return out;
1511 }
1512
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)
1516 {
1517 uint32_t i, x, count;
1518 char *vtime;
1519 const char *key, *val;
1520 asl_string_t *str;
1521
1522 if (msg == NULL) return NULL;
1523
1524 count = asl_msg_count(msg);
1525 if (count == 0) return NULL;
1526
1527 str = asl_string_new(encoding);
1528 if (str == NULL) return NULL;
1529
1530 key = NULL;
1531 val = NULL;
1532 i = 0;
1533
1534 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
1535 {
1536 if (key == NULL) continue;
1537
1538 if (i > 0) asl_string_append_char_no_encoding(str, ' ');
1539
1540 asl_string_append_char_no_encoding(str, '[');
1541 asl_string_append_asl_key(str, key);
1542
1543 if (!strcmp(key, ASL_KEY_TIME))
1544 {
1545 asl_string_append_char_no_encoding(str, ' ');
1546 vtime = NULL;
1547
1548 if (val != NULL) vtime = _asl_time_string(tfmt, val);
1549
1550 if (vtime != NULL)
1551 {
1552 asl_string_append_no_encoding(str, vtime);
1553 free(vtime);
1554 }
1555 else
1556 {
1557 asl_string_append_char_no_encoding(str, '0');
1558 }
1559 }
1560 else if (val != NULL)
1561 {
1562 asl_string_append_char_no_encoding(str, ' ');
1563 asl_string_append(str, val);
1564 }
1565
1566 asl_string_append_char_no_encoding(str, ']');
1567
1568 i++;
1569 }
1570
1571 return str;
1572 }
1573
1574 static asl_string_t *
1575 _asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg)
1576 {
1577 const char *key, *val;
1578 uint32_t i, op, n;
1579
1580 if (msg == NULL) return str;
1581
1582 if (msg->type == ASL_TYPE_QUERY) asl_string_append(str, "Q ");
1583
1584 i = 0;
1585 n = 0;
1586
1587 forever
1588 {
1589 key = NULL;
1590 val = NULL;
1591
1592 i = asl_msg_fetch(msg, i, &key, &val, &op);
1593 if (key != NULL)
1594 {
1595 if (n != 0) asl_string_append_char_no_encoding(str, ' ');
1596 n++;
1597
1598 asl_string_append_char_no_encoding(str, '[');
1599
1600 if (msg->type == ASL_TYPE_QUERY)
1601 {
1602 asl_string_append_op(str, op);
1603 asl_string_append_char_no_encoding(str, ' ');
1604 }
1605
1606 asl_string_append_asl_key(str, key);
1607
1608 if (val != NULL)
1609 {
1610 asl_string_append_char_no_encoding(str, ' ');
1611 asl_string_append(str, val);
1612 }
1613
1614 asl_string_append_char_no_encoding(str, ']');
1615 }
1616
1617 if (i == IndexNull) break;
1618 }
1619
1620 return str;
1621 }
1622
1623 char *
1624 asl_msg_to_string(asl_msg_t *msg, uint32_t *len)
1625 {
1626 char *out;
1627 asl_string_t *str = asl_string_new(ASL_ENCODE_ASL);
1628 if (str == NULL) return NULL;
1629
1630 str = _asl_string_append_asl_msg(str, msg);
1631 *len = asl_string_length(str);
1632 out = asl_string_free_return_bytes(str);
1633 return out;
1634 }
1635
1636 static uint32_t
1637 _asl_msg_op_from_string(char *o)
1638 {
1639 uint32_t op, i;
1640
1641 op = ASL_QUERY_OP_NULL;
1642
1643 if (o == NULL) return op;
1644
1645 for (i = 0; o[i] != '\0'; i++)
1646 {
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;
1659 }
1660
1661 return op;
1662 }
1663
1664 static char *
1665 _asl_msg_get_next_word(char **p, uint32_t *tt, uint32_t spacedel)
1666 {
1667 char *str, *out, c, oval;
1668 uint32_t i, len, n, outlen;
1669
1670 *tt = TOKEN_NULL;
1671
1672 if (p == NULL) return NULL;
1673 if (*p == NULL) return NULL;
1674 if (**p == '\0') return NULL;
1675
1676 /* skip one space if it's there (word separator) */
1677 if (**p == ' ') (*p)++;
1678
1679 /* skip leading white space */
1680 if (spacedel != 0)
1681 {
1682 while ((**p == ' ') || (**p == '\t')) (*p)++;
1683 }
1684
1685 if (**p == '\0') return NULL;
1686 if (**p == '\n') return NULL;
1687
1688 str = *p;
1689
1690 /* opening [ */
1691 if (**p == '[')
1692 {
1693 *tt = TOKEN_OPEN;
1694
1695 (*p)++;
1696 out = malloc(2);
1697 if (out == NULL) return NULL;
1698
1699 out[0] = '[';
1700 out[1] = '\0';
1701 return out;
1702 }
1703
1704 /* scan for token and calulate it's length (input and decoded output len) */
1705 len = 0;
1706 outlen = 0;
1707
1708 forever
1709 {
1710 c = str[len];
1711
1712 /* stop scanning when we hit a delimiter */
1713 if (((spacedel != 0) && (c == ' ')) || (c == ']') || (c == '\0')) break;
1714
1715 if (c == '\\')
1716 {
1717 len++;
1718 c = str[len];
1719 if ((c == 'a') || (c == 'b') || (c == 't') || (c == 'n') || (c == 'v') || (c == 'f') || (c == 'r') || (c == 's') || (c == '[') || (c == '\\') || (c == ']'))
1720 {
1721 }
1722 else if (c == '^')
1723 {
1724 if (str[++len] == '\0') return NULL;
1725 }
1726 else if (c == 'M')
1727 {
1728 if (str[++len] == '\0') return NULL;
1729 if (str[++len] == '\0') return NULL;
1730 }
1731 else if ((c >= '0') && (c <= '3'))
1732 {
1733 if (str[++len] == '\0') return NULL;
1734 if (str[++len] == '\0') return NULL;
1735 }
1736 else
1737 {
1738 return NULL;
1739 }
1740 }
1741
1742 len++;
1743 outlen++;
1744 }
1745
1746 (*p) += len;
1747
1748 if ((len == 0) && (**p == ']'))
1749 {
1750 *tt = TOKEN_CLOSE;
1751 (*p)++;
1752 out = malloc(2);
1753 if (out == NULL) return NULL;
1754
1755 out[0] = ']';
1756 out[1] = '\0';
1757 return out;
1758 }
1759
1760 *tt = TOKEN_INT;
1761
1762 out = malloc(outlen + 1);
1763 if (out == NULL) return NULL;
1764
1765 n = 0;
1766 for (i = 0; i < len; i++)
1767 {
1768 c = str[i];
1769
1770 if (c == '\\')
1771 {
1772 *tt = TOKEN_WORD;
1773
1774 i++;
1775 c = str[i];
1776 if (c == 'a')
1777 {
1778 out[n++] = '\a';
1779 }
1780 else if (c == 'b')
1781 {
1782 out[n++] = '\b';
1783 }
1784 else if (c == 't')
1785 {
1786 out[n++] = '\t';
1787 }
1788 else if (c == 'n')
1789 {
1790 out[n++] = '\n';
1791 }
1792 else if (c == 'v')
1793 {
1794 out[n++] = '\v';
1795 }
1796 else if (c == 'f')
1797 {
1798 out[n++] = '\f';
1799 }
1800 else if (c == 'r')
1801 {
1802 out[n++] = '\r';
1803 }
1804 else if (c == 's')
1805 {
1806 out[n++] = ' ';
1807 }
1808 else if (c == '[')
1809 {
1810 out[n++] = '[';
1811 }
1812 else if (c == '\\')
1813 {
1814 out[n++] = '\\';
1815 }
1816 else if (c == ']')
1817 {
1818 out[n++] = ']';
1819 }
1820 else if (c == '^')
1821 {
1822 i++;
1823 if (str[i] == '?') out[n++] = 127;
1824 else out[n++] = str[i] - 64;
1825 }
1826 else if (c == 'M')
1827 {
1828 i++;
1829 c = str[i];
1830 if (c == '^')
1831 {
1832 i++;
1833 if (str[i] == '?') out[n++] = 255;
1834 else out[n++] = str[i] + 64;
1835 }
1836 else if (c == '-')
1837 {
1838 i++;
1839 out[n++] = str[i] + 128;
1840 }
1841 else
1842 {
1843 *tt = TOKEN_NULL;
1844 free(out);
1845 return NULL;
1846 }
1847
1848 }
1849 else if ((c >= '0') && (c <= '3'))
1850 {
1851 oval = (c - '0') * 64;
1852
1853 i++;
1854 c = str[i];
1855 if ((c < '0') || (c > '7'))
1856 {
1857 *tt = TOKEN_NULL;
1858 free(out);
1859 return NULL;
1860 }
1861
1862 oval += ((c - '0') * 8);
1863
1864 i++;
1865 c = str[i];
1866 if ((c < '0') || (c > '7'))
1867 {
1868 *tt = TOKEN_NULL;
1869 free(out);
1870 return NULL;
1871 }
1872
1873 oval += (c - '0');
1874
1875 out[n++] = oval;
1876 }
1877 else
1878 {
1879 *tt = TOKEN_NULL;
1880 free(out);
1881 return NULL;
1882 }
1883 }
1884 else
1885 {
1886
1887 if ((c < '0') || (c > '9')) *tt = TOKEN_WORD;
1888 out[n++] = c;
1889 }
1890 }
1891
1892 out[n] = '\0';
1893
1894 return out;
1895 }
1896
1897 asl_msg_t *
1898 asl_msg_from_string(const char *buf)
1899 {
1900 uint32_t tt, type, op;
1901 char *k, *v, *o, *p;
1902 asl_msg_t *out;
1903
1904 if (buf == NULL) return NULL;
1905
1906 type = ASL_TYPE_MSG;
1907 p = (char *)buf;
1908
1909 k = _asl_msg_get_next_word(&p, &tt, 1);
1910 if (k == NULL) return NULL;
1911
1912 if (streq(k, "Q"))
1913 {
1914 type = ASL_TYPE_QUERY;
1915 free(k);
1916
1917 k = _asl_msg_get_next_word(&p, &tt, 1);
1918 }
1919 else if (tt == TOKEN_INT)
1920 {
1921 /* Leading integer is a string length - skip it */
1922 free(k);
1923 k = _asl_msg_get_next_word(&p, &tt, 1);
1924 if (k == NULL) return NULL;
1925 }
1926
1927 out = asl_msg_new(ASL_TYPE_MSG);
1928 if (out == NULL) return NULL;
1929
1930 out->type = type;
1931
1932 /* OPEN WORD [WORD [WORD]] CLOSE */
1933 while (k != NULL)
1934 {
1935 op = ASL_QUERY_OP_NULL;
1936
1937 if (tt != TOKEN_OPEN)
1938 {
1939 asl_msg_release(out);
1940 return NULL;
1941 }
1942
1943 free(k);
1944
1945 /* get op for query type */
1946 if (type == ASL_TYPE_QUERY)
1947 {
1948 o = _asl_msg_get_next_word(&p, &tt, 1);
1949 if ((o == NULL) || (tt != TOKEN_WORD))
1950 {
1951 if (o != NULL) free(o);
1952 asl_msg_release(out);
1953 return NULL;
1954 }
1955
1956 op = _asl_msg_op_from_string(o);
1957 free(o);
1958 }
1959
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))
1963 {
1964 if (k != NULL) free(k);
1965 asl_msg_release(out);
1966 return NULL;
1967 }
1968
1969 v = _asl_msg_get_next_word(&p, &tt, 0);
1970 if (tt == TOKEN_INT) tt = TOKEN_WORD;
1971 if (v == NULL)
1972 {
1973 asl_msg_set_key_val_op(out, k, NULL, op);
1974 free(k);
1975 break;
1976 }
1977
1978 if (tt == TOKEN_CLOSE)
1979 {
1980 asl_msg_set_key_val_op(out, k, NULL, op);
1981 }
1982 else if (tt == TOKEN_WORD)
1983 {
1984 asl_msg_set_key_val_op(out, k, v, op);
1985 }
1986 else
1987 {
1988 if (k != NULL) free(k);
1989 if (v != NULL) free(v);
1990 asl_msg_release(out);
1991 return NULL;
1992 }
1993
1994 if (k != NULL) free(k);
1995 if (v != NULL) free(v);
1996
1997 if (tt != TOKEN_CLOSE)
1998 {
1999 k = _asl_msg_get_next_word(&p, &tt, 1);
2000 if (k == NULL) break;
2001
2002 if (tt != TOKEN_CLOSE)
2003 {
2004 asl_msg_release(out);
2005 return NULL;
2006 }
2007
2008 free(k);
2009 }
2010
2011 k = _asl_msg_get_next_word(&p, &tt, 1);
2012 if (k == NULL) break;
2013 }
2014
2015 return out;
2016 }
2017
2018 char *
2019 asl_list_to_string(asl_search_result_t *list, uint32_t *len)
2020 {
2021 uint32_t i;
2022 char tmp[16];
2023 char *out;
2024 asl_string_t *str = asl_string_new(ASL_ENCODE_ASL);
2025 if (str == NULL) return NULL;
2026
2027 if (list == NULL) return NULL;
2028 if (list->count == 0) return NULL;
2029 if (list->msg == NULL) return NULL;
2030
2031 snprintf(tmp, sizeof(tmp), "%u", list->count);
2032 asl_string_append(str, tmp);
2033 asl_string_append_char_no_encoding(str, '\n');
2034
2035 for (i = 0; i < list->count; i++)
2036 {
2037 _asl_string_append_asl_msg(str, list->msg[i]);
2038 asl_string_append_char_no_encoding(str, '\n');
2039 }
2040
2041 *len = asl_string_length(str);
2042 out = asl_string_free_return_bytes(str);
2043 return out;
2044 }
2045
2046 asl_search_result_t *
2047 asl_list_from_string(const char *buf)
2048 {
2049 uint32_t i, n;
2050 const char *p;
2051 asl_search_result_t *out;
2052 asl_msg_t *m;
2053
2054 if (buf == NULL) return NULL;
2055 p = buf;
2056
2057 n = atoi(buf);
2058 if (n == 0) return NULL;
2059
2060 out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
2061 if (out == NULL) return NULL;
2062
2063 out->msg = (asl_msg_t **)calloc(n, sizeof(asl_msg_t *));
2064 if (out->msg == NULL)
2065 {
2066 free(out);
2067 return NULL;
2068 }
2069
2070 for (i = 0; i < n; i++)
2071 {
2072 p = strchr(p, '\n');
2073 if (p == NULL)
2074 {
2075 aslresponse_free((aslresponse)out);
2076 return NULL;
2077 }
2078
2079 p++;
2080
2081 m = asl_msg_from_string(p);
2082 if (m == NULL)
2083 {
2084 aslresponse_free((aslresponse)out);
2085 return NULL;
2086 }
2087
2088 out->msg[i] = (asl_msg_t *)m;
2089 out->count += 1;
2090 }
2091
2092 return out;
2093 }
2094
2095 static const char *
2096 _asl_level_string(int level)
2097 {
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;
2106 return "unknown";
2107 }
2108
2109 /*
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!
2113 */
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)
2116 {
2117 uint32_t i, get_fmt;
2118 char *key, *fmt;
2119 const char *mval;
2120
2121 if (str == NULL) return NULL;
2122 if (msg == NULL) return str;
2123 if (kf == NULL) return str;
2124
2125 key = NULL;
2126 fmt = NULL;
2127 get_fmt = 0;
2128
2129 for (i = 0; kf[i] != '\0'; i++)
2130 {
2131 if (kf[i] == ')')
2132 {
2133 kf[i] = '\0';
2134 get_fmt = 1;
2135 }
2136 else if (kf[i] != '(')
2137 {
2138 if (key == NULL) key = kf + i;
2139 else if ((get_fmt == 1) && (fmt == NULL)) fmt = kf + i;
2140 }
2141 }
2142
2143 if (key == NULL) return str;
2144
2145 asl_msg_lookup(msg, key, &mval, NULL);
2146 if (mval == NULL) return str;
2147
2148 if (!strcmp(key, ASL_KEY_TIME))
2149 {
2150 char *fval = NULL;
2151
2152 /* format in $((Time)(fmt)) overrides tfmt */
2153 if (fmt == NULL)
2154 {
2155 fval = _asl_time_string(tfmt, mval);
2156 }
2157 else
2158 {
2159 fval = _asl_time_string(fmt, mval);
2160 }
2161
2162 if (fval != NULL)
2163 {
2164 asl_string_append_no_encoding(str, fval);
2165 free(fval);
2166 }
2167 else
2168 {
2169 asl_string_append_char_no_encoding(str, '0');
2170 }
2171
2172 return str;
2173 }
2174
2175 /* Level: num str */
2176 if (!strcmp(key, ASL_KEY_LEVEL))
2177 {
2178 if (fmt == NULL)
2179 {
2180 asl_string_append_no_encoding(str, mval);
2181 }
2182 else if (!strcmp(fmt, "str"))
2183 {
2184 mval = _asl_level_string(atoi(mval));
2185 asl_string_append_no_encoding(str, mval);
2186 }
2187 else
2188 {
2189 asl_string_append_no_encoding(str, mval);
2190 }
2191
2192 return str;
2193 }
2194
2195 return asl_string_append(str, mval);
2196 }
2197
2198 /*
2199 * format a message for printing
2200 * out parameter len returns string length including trailing NUL
2201 */
2202 char *
2203 asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t text_encoding, uint32_t *len)
2204 {
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;
2208 uint32_t x, cursor;
2209 asl_string_t *str;
2210 uint8_t *b64;
2211
2212 out = NULL;
2213 *len = 0;
2214
2215 if (msg == NULL) return NULL;
2216
2217 mf = MFMT_RAW;
2218
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;
2225 else mf = MFMT_STR;
2226
2227 if (mf == MFMT_RAW)
2228 {
2229 str = asl_msg_to_string_raw(text_encoding, msg, tfmt);
2230 asl_string_append_char_no_encoding(str, '\n');
2231
2232 *len = asl_string_length(str);
2233 out = asl_string_free_return_bytes(str);
2234 return out;
2235 }
2236
2237 if (mf == MFMT_MSG)
2238 {
2239 vmessage = NULL;
2240
2241 if (asl_msg_lookup(msg, ASL_KEY_MSG, &vmessage, NULL) != 0) return NULL;
2242
2243 str = asl_string_new(text_encoding);
2244 if (str == NULL) return NULL;
2245
2246 asl_string_append(str, vmessage);
2247 asl_string_append_char_no_encoding(str, '\n');
2248
2249 *len = asl_string_length(str);
2250 out = asl_string_free_return_bytes(str);
2251 return out;
2252 }
2253
2254 if ((mf == MFMT_STD) || (mf == MFMT_BSD))
2255 {
2256 /* COMMON: Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/
2257 /* BSD: <COMMON>: message */
2258 /* STD: <COMMON> <Level>: message */
2259
2260 v = NULL;
2261 vhost = NULL;
2262 vsender = NULL;
2263 vpid = NULL;
2264 vmessage = NULL;
2265 vlevel = NULL;
2266 vrefproc = NULL;
2267 vrefpid = NULL;
2268
2269 asl_msg_lookup(msg, ASL_KEY_TIME, &v, NULL);
2270 vtime = _asl_time_string(tfmt, v);
2271
2272 level = 7;
2273 asl_msg_lookup(msg, ASL_KEY_LEVEL, &vlevel, NULL);
2274 if (vlevel != NULL) level = atoi(vlevel);
2275
2276 asl_msg_lookup(msg, ASL_KEY_HOST, &vhost, NULL);
2277 if (vhost == NULL) vhost = "unknown";
2278
2279 asl_msg_lookup(msg, ASL_KEY_SENDER, &vsender, NULL);
2280 if (vsender == NULL) vsender = "unknown";
2281
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);
2286
2287 /* COMMON */
2288 str = asl_string_new(text_encoding);
2289 if (str == NULL) return NULL;
2290
2291 if (vtime != NULL)
2292 {
2293 asl_string_append(str, vtime);
2294 free(vtime);
2295 }
2296 else
2297 {
2298 asl_string_append_char_no_encoding(str, '0');
2299 }
2300
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);
2305
2306 if ((vpid != NULL) && (strcmp(vpid, "-1")))
2307 {
2308 asl_string_append_char_no_encoding(str, '[');
2309 asl_string_append(str, vpid);
2310 asl_string_append_char_no_encoding(str, ']');
2311 }
2312
2313 if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_no_encoding(str, " (");
2314
2315 if (vrefproc != NULL) asl_string_append(str, vrefproc);
2316 if (vrefpid != NULL)
2317 {
2318 asl_string_append_char_no_encoding(str, '[');
2319 asl_string_append(str, vrefpid);
2320 asl_string_append_char_no_encoding(str, ']');
2321 }
2322
2323 if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_char_no_encoding(str, ')');
2324
2325 if (mf == MFMT_STD)
2326 {
2327 asl_string_append_no_encoding(str, " <");
2328 asl_string_append(str, _asl_level_string(level));
2329 asl_string_append_char_no_encoding(str, '>');
2330 }
2331
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');
2335
2336 *len = asl_string_length(str);
2337 out = asl_string_free_return_bytes(str);
2338 return out;
2339 }
2340
2341 if (mf == MFMT_XML)
2342 {
2343 str = asl_string_new(text_encoding);
2344 if (str == NULL) return NULL;
2345
2346 asl_string_append_char_no_encoding(str, '\t');
2347 asl_string_append(str, "<dict>");
2348 asl_string_append_char_no_encoding(str, '\n');
2349
2350 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
2351 {
2352 if (asl_is_utf8(key) == 1)
2353 {
2354 asl_string_append_xml_tag(str, "key", key);
2355 if (!strcmp(key, ASL_KEY_TIME))
2356 {
2357 vtime = _asl_time_string(tfmt, val);
2358 if (vtime != NULL)
2359 {
2360 asl_string_append_xml_tag(str, "string", vtime);
2361 free(vtime);
2362 }
2363 else
2364 {
2365 asl_string_append_xml_tag(str, "string", "0");
2366 }
2367 }
2368 else
2369 {
2370 if (asl_is_utf8(val) == 1) asl_string_append_xml_tag(str, "string", val);
2371 else
2372 {
2373 b64 = asl_b64_encode((uint8_t *)val, strlen(val));
2374 asl_string_append_xml_tag(str, "data", (char *)b64);
2375 free(b64);
2376 }
2377 }
2378 }
2379 }
2380
2381 asl_string_append_char_no_encoding(str, '\t');
2382 asl_string_append(str, "</dict>");
2383 asl_string_append_char_no_encoding(str, '\n');
2384
2385 *len = asl_string_length(str);
2386 out = asl_string_free_return_bytes(str);
2387 return out;
2388 }
2389
2390 /*
2391 * Custom format
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 "$".
2398 */
2399
2400 str = asl_string_new(text_encoding);
2401 if (str == NULL) return NULL;
2402
2403 /*
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.
2409 */
2410
2411 x = strlen(mfmt);
2412 if (x <= sizeof(skey))
2413 {
2414 k = skey;
2415 }
2416 else
2417 {
2418 k = malloc(x);
2419 if (k == NULL) return NULL;
2420 }
2421
2422 cursor = 0;
2423
2424 for (i = 0; mfmt[i] != '\0'; i++)
2425 {
2426 if (mfmt[i] == '$')
2427 {
2428 paren = 0;
2429
2430 /* scan key, (key) or ((key)(format)) */
2431 for (j = i + 1; mfmt[j] != 0; j++)
2432 {
2433 if (mfmt[j] == '(')
2434 {
2435 paren++;
2436 }
2437 else if (mfmt[j] == ')')
2438 {
2439 if (paren > 0) paren--;
2440 if (paren == 0)
2441 {
2442 j++;
2443 break;
2444 }
2445 }
2446 else if (((mfmt[j] == ' ') || (mfmt[j] == '\t')) && (paren == 0)) break;
2447 }
2448
2449 /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */
2450 l = j - (i + 1);
2451 memcpy(k, mfmt+i+1, l);
2452 k[l] = '\0';
2453 _asl_string_append_value_for_key_format(str, msg, k, tfmt);
2454
2455 i = j - 1;
2456 continue;
2457 }
2458
2459 if (mfmt[i] == '\\')
2460 {
2461 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]))
2475 {
2476 oval = mfmt[i] - '0';
2477 if (isdigit(mfmt[i+1]))
2478 {
2479 i++;
2480 oval = (oval * 8) + (mfmt[i] - '0');
2481 if (isdigit(mfmt[i+1]))
2482 {
2483 i++;
2484 oval = (oval * 8) + (mfmt[i] - '0');
2485 }
2486 }
2487 c = oval;
2488 asl_string_append_char_no_encoding(str, c);
2489 }
2490 continue;
2491 }
2492
2493 if (mfmt[i] == '\0') break;
2494 asl_string_append_char_no_encoding(str, mfmt[i]);
2495 }
2496
2497 if (k != skey) free(k);
2498
2499 asl_string_append_char_no_encoding(str, '\n');
2500
2501 *len = asl_string_length(str);
2502 out = asl_string_free_return_bytes(str);
2503 return out;
2504 }
2505
2506 /*
2507 * OLD ASLMSG COMPATIBILITY
2508 */
2509 const char *
2510 asl_key(aslmsg msg, uint32_t n)
2511 {
2512 uint32_t slot, i;
2513 asl_msg_t *page;
2514
2515 i = 0;
2516 for (page = (asl_msg_t *)msg; page != NULL; page = page->next)
2517 {
2518 for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++)
2519 {
2520 if (page->key[slot] != ASL_MSG_SLOT_FREE)
2521 {
2522 if (i == n) return _asl_msg_slot_key(page, slot);
2523 i++;
2524 }
2525 }
2526 }
2527
2528 return NULL;
2529 }
2530
2531 aslmsg
2532 asl_new(uint32_t type)
2533 {
2534 return (aslmsg)asl_msg_new(type);
2535 }
2536
2537 int
2538 asl_set(aslmsg msg, const char *key, const char *value)
2539 {
2540 return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, IndexNull);
2541 }
2542
2543 int
2544 asl_set_query(aslmsg msg, const char *key, const char *value, uint32_t op)
2545 {
2546 return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, op);
2547 }
2548
2549 int
2550 asl_unset(aslmsg msg, const char *key)
2551 {
2552 asl_msg_unset((asl_msg_t *)msg, key);
2553 return 0;
2554 }
2555
2556 const char *
2557 asl_get(aslmsg msg, const char *key)
2558 {
2559 const char *val;
2560 int status;
2561
2562 val = NULL;
2563 status = asl_msg_lookup((asl_msg_t *)msg, key, &val, NULL);
2564 if (status != 0) return NULL;
2565 return val;
2566 }
2567
2568 void
2569 asl_free(aslmsg msg)
2570 {
2571 asl_msg_release((asl_msg_t *)msg);
2572 }
2573
2574 /* aslresponse */
2575
2576 /*
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
2580 */
2581 aslmsg
2582 aslresponse_next(aslresponse r)
2583 {
2584 asl_search_result_t *res;
2585 asl_msg_t *m;
2586
2587 res = (asl_search_result_t *)r;
2588 if (res == NULL) return NULL;
2589
2590 if (res->curr >= res->count) return NULL;
2591 m = res->msg[res->curr];
2592 res->curr++;
2593
2594 return (aslmsg)m;
2595 }
2596
2597 /*
2598 * aslresponse_free: Free a response returned from asl_search()
2599 * a: a response returned from asl_search()
2600 */
2601 void
2602 aslresponse_free(aslresponse r)
2603 {
2604 asl_search_result_t *res;
2605 uint32_t i;
2606
2607 res = (asl_search_result_t *)r;
2608 if (res == NULL) return;
2609
2610 for (i = 0; i < res->count; i++) asl_msg_release(res->msg[i]);
2611 free(res->msg);
2612 free(res);
2613 }