]> git.saurik.com Git - apple/libc.git/blob - gen/asl.c
a5d07fc09d307bbb512e36f5353778c244b738a0
[apple/libc.git] / gen / asl.c
1 /*
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <string.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <syslog.h>
33 #include <errno.h>
34 #include <time.h>
35 #include <crt_externs.h>
36 #include <asl.h>
37 #include <asl_private.h>
38 #include <regex.h>
39 #include <notify.h>
40 #include <mach/mach.h>
41 #include <mach/std_types.h>
42 #include <mach/mig.h>
43 #include <mach/mach_types.h>
44 #include <sys/types.h>
45 #include <servers/bootstrap.h>
46 #include <pthread.h>
47 #include <asl_ipc.h>
48
49 #define ASL_SERVICE_NAME "com.apple.system.logger"
50
51 #define streq(A, B) (strcmp(A, B) == 0)
52 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
53
54 #define forever for(;;)
55
56 #define TOKEN_NULL 0
57 #define TOKEN_OPEN 1
58 #define TOKEN_CLOSE 2
59 #define TOKEN_WORD 3
60 #define TOKEN_INT 4
61
62 #define MFMT_RAW 0
63 #define MFMT_STD 1
64 #define MFMT_BSD 2
65 #define MFMT_XML 3
66 #define MFMT_STR 4
67 #define MFMT_MSG 5
68
69 #define TFMT_SEC 0
70 #define TFMT_UTC 1
71 #define TFMT_LCL 2
72
73 #define ENCODE_NONE 0
74 #define ENCODE_VIS 1
75 #define ENCODE_ASL 2
76
77 #define XML_TAG_KEY 0
78 #define XML_TAG_STRING 1
79 #define XML_TAG_DATA 2
80
81 #define FETCH_BATCH 256
82
83 /* forward */
84 time_t asl_parse_time(const char *);
85 const char *asl_syslog_faciliy_num_to_name(int n);
86 __private_extern__ asl_client_t *_asl_open_default();
87
88 /* notify SPI */
89 uint32_t notify_register_plain(const char *name, int *out_token);
90
91 /* from asl_util.c */
92 int _asl_server_socket(int *sock, struct sockaddr_un *server);
93 int asl_is_utf8(const char *str);
94 uint8_t *asl_b64_encode(const uint8_t *buf, size_t len);
95
96 /* character encoding lengths */
97 static const uint8_t char_encode_len[128] =
98 {
99 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
100 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
101 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3
103 };
104
105 static const char *cvis_7_13 = "abtnvfr";
106
107 typedef struct
108 {
109 int notify_count;
110 int notify_token;
111 int master_token;
112 char *sender;
113 pthread_mutex_t lock;
114 asl_client_t *asl;
115 } _asl_global_t;
116
117 #ifndef BUILDING_VARIANT
118 __private_extern__ _asl_global_t _asl_global = {0, -1, -1, NULL, PTHREAD_MUTEX_INITIALIZER, NULL};
119
120 static mach_port_t asl_server_port = MACH_PORT_NULL;
121
122 static int
123 _asl_connect(asl_client_t *asl)
124 {
125 if (asl->sock >= 0) return 0;
126
127 return _asl_server_socket(&asl->sock, &asl->server);
128 }
129
130 static int
131 _asl_notify_open(int do_lock)
132 {
133 char *notify_name;
134 const char *prefix;
135 uint32_t status;
136
137 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
138
139 _asl_global.notify_count++;
140
141 if (_asl_global.notify_token != -1)
142 {
143 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
144 return 0;
145 }
146
147 notify_name = NULL;
148
149 prefix = NOTIFY_PREFIX_USER;
150 if (getuid() == 0) prefix = NOTIFY_PREFIX_SYSTEM;
151
152 if (_asl_global.master_token == -1)
153 {
154 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
155 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
156 }
157
158 asprintf(&notify_name, "%s.%d", prefix, getpid());
159
160 if (notify_name != NULL)
161 {
162 status = notify_register_plain(notify_name, &_asl_global.notify_token);
163 free(notify_name);
164 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
165 }
166
167 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
168
169 if (_asl_global.notify_token == -1) return -1;
170 return 0;
171 }
172
173 static void
174 _asl_notify_close()
175 {
176 pthread_mutex_lock(&_asl_global.lock);
177
178 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
179
180 if (_asl_global.notify_count > 0)
181 {
182 pthread_mutex_unlock(&_asl_global.lock);
183 return;
184 }
185
186 if (_asl_global.master_token > 0) notify_cancel(_asl_global.master_token);
187 _asl_global.master_token = -1;
188
189 if (_asl_global.notify_token > 0) notify_cancel(_asl_global.notify_token);
190 _asl_global.notify_token = -1;
191
192 pthread_mutex_unlock(&_asl_global.lock);
193 }
194
195 aslclient
196 asl_open(const char *ident, const char *facility, uint32_t opts)
197 {
198 char *name, *x;
199 asl_client_t *asl;
200
201 asl = (asl_client_t *)calloc(1, sizeof(asl_client_t));
202 if (asl == NULL)
203 {
204 errno = ENOMEM;
205 return NULL;
206 }
207
208 asl->options = opts;
209
210 asl->sock = -1;
211
212 if (asl->options & ASL_OPT_NO_DELAY)
213 {
214 if (_asl_connect(asl) < 0)
215 {
216 free(asl);
217 return NULL;
218 }
219 }
220
221 asl->pid = getpid();
222 asl->uid = getuid();
223 asl->gid = getgid();
224
225 asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
226
227 if (ident != NULL)
228 {
229 asl->name = strdup(ident);
230 if (asl->name == NULL)
231 {
232 close(asl->sock);
233 free(asl);
234 return NULL;
235 }
236 }
237 else
238 {
239 name = *(*_NSGetArgv());
240 if (name != NULL)
241 {
242 x = strrchr(name, '/');
243 if (x != NULL) x++;
244 else x = name;
245 asl->name = strdup(x);
246 if (asl->name == NULL)
247 {
248 close(asl->sock);
249 free(asl);
250 return NULL;
251 }
252 }
253 }
254
255 asl->facility = NULL;
256 if (facility != NULL) asl->facility = strdup(facility);
257 else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER));
258 if (asl->facility == NULL)
259 {
260 close(asl->sock);
261 free(asl);
262 return NULL;
263 }
264
265 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
266
267 if (asl->options & ASL_OPT_STDERR) asl_add_output((aslclient)asl, fileno(stderr), ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL);
268
269 return (aslclient)asl;
270 }
271
272 void
273 asl_close(aslclient ac)
274 {
275 asl_client_t *asl;
276 uint32_t i;
277
278 asl = (asl_client_t *)ac;
279 if (asl == NULL) return;
280
281 if (asl->sock >= 0) close(asl->sock);
282 if (asl->name != NULL) free(asl->name);
283 if (asl->facility != NULL) free(asl->facility);
284 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_close();
285 if (asl->fd_list != NULL) free(asl->fd_list);
286
287 if (asl->fd_mfmt != NULL)
288 {
289 for (i = 0; i < asl->fd_count; i++) if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
290 free(asl->fd_mfmt);
291 }
292
293 if (asl->fd_tfmt != NULL)
294 {
295 for (i = 0; i < asl->fd_count; i++) if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
296 free(asl->fd_tfmt);
297 }
298
299 memset(asl, 0, sizeof(asl_client_t));
300 free(asl);
301 }
302
303 __private_extern__ asl_client_t *
304 _asl_open_default()
305 {
306 pthread_mutex_lock(&_asl_global.lock);
307 if (_asl_global.asl != NULL)
308 {
309 pthread_mutex_unlock(&_asl_global.lock);
310 return _asl_global.asl;
311 }
312
313 /*
314 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
315 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
316 * which locks _asl_global.lock.
317 */
318 _asl_global.asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
319
320 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
321 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
322
323 /* Now call _asl_notify_open(0) to finish the work */
324 _asl_notify_open(0);
325
326 pthread_mutex_unlock(&_asl_global.lock);
327
328 return _asl_global.asl;
329 }
330
331 static uint32_t
332 _asl_msg_index(asl_msg_t *msg, const char *k)
333 {
334 uint32_t i;
335
336 if (msg == NULL) return (uint32_t)-1;
337 if (k == NULL) return (uint32_t)-1;
338
339 for (i = 0; i < msg->count; i++)
340 {
341 if (msg->key[i] == NULL) continue;
342 if (streq(msg->key[i], k)) return i;
343 }
344
345 return (uint32_t)-1;
346 }
347
348 static void
349 _asl_encode_char(char **m, uint32_t *x, uint32_t c, uint32_t encode, uint32_t encode_space)
350 {
351 char *p;
352 int meta;
353
354 meta = 0;
355
356 p = *m + *x - 1;
357
358 /* NUL is not allowed */
359 if (c == 0) return;
360
361 /* Meta chars get \M prefix */
362 if (c >= 128)
363 {
364 /* except meta-space, which is \240 */
365 if (c == 160)
366 {
367 *p++ = '\\';
368 *p++ = '2';
369 *p++ = '4';
370 *p++ = '0';
371 *p = '\0';
372 *x = *x + 4;
373 return;
374 }
375
376 *p++ = '\\';
377 *p++ = 'M';
378 *p = '\0';
379 *x = *x + 2;
380 c &= 0x7f;
381 meta = 1;
382 }
383
384 /* space is either ' ' or \s */
385 if (c == 32)
386 {
387 if (encode_space == 0)
388 {
389 *p++ = ' ';
390 *p = '\0';
391 *x = *x + 1;
392 return;
393 }
394
395 *p++ = '\\';
396 *p++ = 's';
397 *p = '\0';
398 *x = *x + 2;
399 return;
400 }
401
402 /* \ is escaped */
403 if ((meta == 0) && (c == 92))
404 {
405 *p++ = '\\';
406 *p++ = c;
407 *p = '\0';
408 *x = *x + 2;
409 return;
410 }
411
412 /* [ and ] ane escaped in ASL encoding */
413 if ((encode == ENCODE_ASL) && (meta == 0) && ((c == 91) || (c == 93)))
414 {
415 *p++ = '\\';
416 *p++ = c;
417 *p = '\0';
418 *x = *x + 2;
419 return;
420 }
421
422 /* DEL is \^? */
423 if (c == 127)
424 {
425 if (meta == 0)
426 {
427 *p++ = '\\';
428 *x = *x + 1;
429 }
430
431 *p++ = '^';
432 *p++ = '?';
433 *p = '\0';
434 *x = *x + 2;
435 return;
436 }
437
438 /* 33-126 are printable (add a '-' prefix for meta) */
439 if ((c >= 33) && (c <= 126))
440 {
441 if (meta == 1)
442 {
443 *p++ = '-';
444 *x = *x + 1;
445 }
446
447 *p++ = c;
448 *p = '\0';
449 *x = *x + 1;
450 return;
451 }
452
453 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
454 if ((meta == 0) && (c >= 7) && (c <= 13))
455 {
456 *p++ = '\\';
457 *p++ = cvis_7_13[c - 7];
458 *p = '\0';
459 *x = *x + 2;
460 return;
461 }
462
463 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
464 if ((c >= 0) && (c <= 31))
465 {
466 if (meta == 0)
467 {
468 *p++ = '\\';
469 *x = *x + 1;
470 }
471
472 *p++ = '^';
473 *p++ = 64 + c;
474 *p = '\0';
475 *x = *x + 2;
476 return;
477 }
478
479 return;
480 }
481
482 static void
483 _asl_append_string(char **m, uint32_t *x, const char *s, uint32_t encode, uint32_t escspace)
484 {
485 uint32_t i, n, spextra;
486 uint8_t c;
487
488 if (m == NULL) return;
489 if (x == NULL) return;
490 if (s == NULL) return;
491
492 if (encode == ENCODE_NONE)
493 {
494 n = strlen(s);
495 if (n == 0) return;
496
497 if (*m == NULL)
498 {
499 *m = malloc(n + 1);
500 *x = 1;
501 }
502 else
503 {
504 *m = reallocf(*m, n + (*x));
505 }
506
507 if (*m == NULL) return;
508
509 memcpy((*m) + (*x) - 1, s, n + 1);
510 *x += n;
511
512 return;
513 }
514
515 spextra = 0;
516
517 if (escspace != 0) spextra = 1;
518
519 n = 0;
520 for (i = 0; s[i] != '\0'; i++)
521 {
522 c = s[i];
523
524 if (c >= 128)
525 {
526 n += 4;
527 }
528 else if ((c == 91) || (c == 93))
529 {
530 if (encode == ENCODE_ASL) n += 2;
531 else n += 1;
532 }
533 else
534 {
535 n += char_encode_len[c];
536 if (c == 32) n += spextra;
537 }
538 }
539
540 if (n == 0) return;
541
542 if (*m == NULL)
543 {
544 *m = malloc(n + 1);
545 *x = 1;
546 }
547 else
548 {
549 *m = reallocf(*m, n + (*x));
550 }
551
552 if (*m == NULL) return;
553
554 for (i = 0; s[i] != '\0'; i++)
555 {
556 c = s[i];
557 _asl_encode_char(m, x, c, encode, escspace);
558 }
559
560 return;
561 }
562
563 static void
564 _asl_append_xml_string(char **m, uint32_t *x, char *s)
565 {
566 uint32_t i, n;
567 uint8_t c;
568 char tmp[8], *p;
569
570 if (m == NULL) return;
571 if (x == NULL) return;
572 if (s == NULL) return;
573
574 n = 0;
575 for (i = 0; s[i] != '\0'; i++)
576 {
577 c = s[i];
578
579 /*
580 * XML wants &amp; &lt; &gt; &quot; and &apos;
581 * We use &#xnn; for control chars.
582 * Everything else just gets printed "as is" (we know the input is UTF8)
583 */
584 if (c == '&') n += 5;
585 else if (c == '<') n += 4;
586 else if (c == '>') n += 4;
587 else if (c == '"') n += 6;
588 else if (c == '\'') n += 6;
589 else if (iscntrl(c)) n += 6;
590 else n += 1;
591 }
592
593 if (n == 0) return;
594
595 if (*m == NULL)
596 {
597 *m = malloc(n + 1);
598 *x = 1;
599 }
600 else
601 {
602 *m = reallocf(*m, n + (*x));
603 }
604
605 if (*m == NULL) return;
606
607 for (i = 0; s[i] != '\0'; i++)
608 {
609 c = s[i];
610
611 if (c == '&')
612 {
613 p = *m + *x - 1;
614 memcpy(p, "&amp;", 5);
615 p += 5;
616 *p = '\0';
617 *x = *x + 5;
618 }
619 else if (c == '<')
620 {
621 p = *m + *x - 1;
622 memcpy(p, "&lt;", 4);
623 p += 4;
624 *p = '\0';
625 *x = *x + 4;
626 }
627 else if (c == '>')
628 {
629 p = *m + *x - 1;
630 memcpy(p, "&gt;", 4);
631 p += 4;
632 *p = '\0';
633 *x = *x + 4;
634 }
635 else if (c == '"')
636 {
637 p = *m + *x - 1;
638 memcpy(p, "&quot;", 6);
639 p += 6;
640 *p = '\0';
641 *x = *x + 6;
642 }
643 else if (c == '\'')
644 {
645 p = *m + *x - 1;
646 memcpy(p, "&apos;", 6);
647 p += 6;
648 *p = '\0';
649 *x = *x + 6;
650 }
651 else if (iscntrl(c))
652 {
653 snprintf(tmp, sizeof(tmp), "&#x%02hhu;", c);
654 p = *m + *x - 1;
655 memcpy(p, tmp, 6);
656 p += 6;
657 *p = '\0';
658 *x = *x + 6;
659 }
660 else
661 {
662 p = *m + *x - 1;
663 *p++ = c;
664 *p = '\0';
665 *x = *x + 1;
666 }
667 }
668
669 return;
670 }
671
672 static void
673 _asl_append_xml_tag(char **m, uint32_t *x, int tag, char *s)
674 {
675 char *b64;
676
677 if (m == NULL) return;
678 if (x == NULL) return;
679
680 if (tag == XML_TAG_KEY)
681 {
682 _asl_append_string(m, x, "\t\t<key>", ENCODE_NONE, 0);
683 _asl_append_xml_string(m, x, s);
684 _asl_append_string(m, x, "</key>\n", ENCODE_NONE, 0);
685 return;
686 }
687
688 if (tag == XML_TAG_STRING)
689 {
690 _asl_append_string(m, x, "\t\t<string>", ENCODE_NONE, 0);
691 _asl_append_xml_string(m, x, s);
692 _asl_append_string(m, x, "</string>\n", ENCODE_NONE, 0);
693 return;
694 }
695
696 if (tag == XML_TAG_DATA)
697 {
698 _asl_append_string(m, x, "\t\t<data>", ENCODE_NONE, 0);
699 b64 = (char *)asl_b64_encode((uint8_t *)s, strlen(s));
700 if (b64 != NULL)
701 {
702 _asl_append_string(m, x, b64, ENCODE_NONE, 0);
703 free(b64);
704 }
705 _asl_append_string(m, x, "</data>\n", ENCODE_NONE, 0);
706 return;
707 }
708 }
709
710 static void
711 _asl_append_op(char **m, uint32_t *x, uint32_t op)
712 {
713 char opstr[8];
714 uint32_t i;
715
716 if (m == NULL) return;
717 if (x == NULL) return;
718
719 if (op == ASL_QUERY_OP_NULL) return _asl_append_string(m, x, ".", ENCODE_NONE, 0);
720
721 i = 0;
722 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C';
723
724 if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R';
725
726 if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N';
727
728 if (op & ASL_QUERY_OP_PREFIX)
729 {
730 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S';
731 else opstr[i++] = 'A';
732 }
733 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z';
734
735 switch (op & ASL_QUERY_OP_TRUE)
736 {
737 case ASL_QUERY_OP_EQUAL:
738 opstr[i++] = '=';
739 break;
740 case ASL_QUERY_OP_GREATER:
741 opstr[i++] = '>';
742 break;
743 case ASL_QUERY_OP_GREATER_EQUAL:
744 opstr[i++] = '>';
745 opstr[i++] = '=';
746 break;
747 case ASL_QUERY_OP_LESS:
748 opstr[i++] = '<';
749 break;
750 case ASL_QUERY_OP_LESS_EQUAL:
751 opstr[i++] = '<';
752 opstr[i++] = '=';
753 break;
754 case ASL_QUERY_OP_NOT_EQUAL:
755 opstr[i++] = '!';
756 break;
757 case ASL_QUERY_OP_TRUE:
758 opstr[i++] = 'T';
759 break;
760 default:
761 break;
762 }
763
764 if (i == 0) return _asl_append_string(m, x, ".", ENCODE_NONE, 0);
765
766 opstr[i++] = '\0';
767 return _asl_append_string(m, x, opstr, ENCODE_NONE, 0);
768 }
769
770 static char *
771 _asl_time_string(int fmt, const char *str)
772 {
773 time_t tick;
774 struct tm *stm;
775 char *ltime;
776 char *out;
777 char ltbuf[32];
778 out = NULL;
779
780 tick = 0;
781 if (str != NULL) tick = asl_parse_time(str);
782
783 if (fmt == TFMT_SEC)
784 {
785 asprintf(&out, "%lu", tick);
786 return out;
787 }
788
789 if (fmt == TFMT_UTC)
790 {
791 stm = gmtime(&tick);
792 asprintf(&out, "%d.%02d.%02d %02d:%02d:%02d UTC", stm->tm_year + 1900, stm->tm_mon + 1, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec);
793 return out;
794 }
795
796 if (fmt == TFMT_LCL)
797 {
798 ltime = ctime_r(&tick, ltbuf);
799 if (ltime == NULL) return NULL;
800 ltime[19] = '\0';
801 asprintf(&out, "%s", ltime);
802 return out;
803 }
804
805 return NULL;
806 }
807
808 static char *
809 _asl_msg_to_string_time_fmt(asl_msg_t *msg, uint32_t *len, int tf)
810 {
811 uint32_t i, outlen;
812 char *out, *s;
813
814 *len = 0;
815
816 if (msg == NULL) return NULL;
817
818 s = NULL;
819 out = NULL;
820 outlen = 0;
821
822 if (msg->count == 0)
823 {
824 if (out == NULL) return NULL;
825 *len = outlen;
826 return out;
827 }
828
829 for (i = 0; i < msg->count; i++)
830 {
831 if (msg->key[i] == NULL) continue;
832 if (i > 0) _asl_append_string(&out, &outlen, " [", ENCODE_NONE, 0);
833 else _asl_append_string(&out, &outlen, "[", ENCODE_NONE, 0);
834
835 _asl_append_string(&out, &outlen, msg->key[i], ENCODE_ASL, 1);
836
837 if ((tf != TFMT_SEC) && (!strcmp(msg->key[i], ASL_KEY_TIME)))
838 {
839 s = _asl_time_string(tf, msg->val[i]);
840 if (s != NULL)
841 {
842 _asl_append_string(&out, &outlen, " ", ENCODE_NONE, 0);
843 _asl_append_string(&out, &outlen, s, ENCODE_ASL, 0);
844 }
845 }
846 else if (msg->val[i] != NULL)
847 {
848 _asl_append_string(&out, &outlen, " ", ENCODE_NONE, 0);
849 _asl_append_string(&out, &outlen, msg->val[i], ENCODE_ASL, 0);
850 }
851
852 _asl_append_string(&out, &outlen, "]", ENCODE_NONE, 0);
853 }
854
855 _asl_append_string(&out, &outlen, "\n", ENCODE_NONE, 0);
856
857 *len = outlen;
858 return out;
859 }
860
861 char *
862 asl_msg_to_string(asl_msg_t *msg, uint32_t *len)
863 {
864 uint32_t i, outlen;
865 char *out, *s;
866
867 *len = 0;
868
869 if (msg == NULL) return NULL;
870
871 s = NULL;
872 out = NULL;
873 outlen = 0;
874
875 if (msg->type == ASL_TYPE_QUERY)
876 {
877 _asl_append_string(&out, &outlen, "Q ", ENCODE_NONE, 0);
878 if (out == NULL) return NULL;
879 }
880
881 if (msg->count == 0)
882 {
883 if (out == NULL) return NULL;
884 *len = outlen;
885 return out;
886 }
887
888 for (i = 0; i < msg->count; i++)
889 {
890 if (msg->key[i] == NULL) continue;
891
892 if (i > 0) _asl_append_string(&out, &outlen, " [", ENCODE_NONE, 0);
893 else _asl_append_string(&out, &outlen, "[", ENCODE_NONE, 0);
894
895 if (msg->type == ASL_TYPE_QUERY)
896 {
897 _asl_append_op(&out, &outlen, msg->op[i]);
898 _asl_append_string(&out, &outlen, " ", ENCODE_NONE, 0);
899 }
900
901 _asl_append_string(&out, &outlen, msg->key[i], ENCODE_ASL, 1);
902
903 if (msg->val[i] != NULL)
904 {
905 _asl_append_string(&out, &outlen, " ", ENCODE_NONE, 0);
906 _asl_append_string(&out, &outlen, msg->val[i], ENCODE_ASL, 0);
907 }
908
909 _asl_append_string(&out, &outlen, "]", ENCODE_NONE, 0);
910 }
911
912 *len = outlen;
913 return out;
914 }
915
916 static uint32_t
917 _asl_msg_op_from_string(char *o)
918 {
919 uint32_t op, i;
920
921 op = ASL_QUERY_OP_NULL;
922
923 if (o == NULL) return op;
924
925 for (i = 0; o[i] != '\0'; i++)
926 {
927 if (o[i] == '.') return ASL_QUERY_OP_NULL;
928 if (o[i] == 'C') op |= ASL_QUERY_OP_CASEFOLD;
929 if (o[i] == 'R') op |= ASL_QUERY_OP_REGEX;
930 if (o[i] == 'N') op |= ASL_QUERY_OP_NUMERIC;
931 if (o[i] == 'S') op |= ASL_QUERY_OP_SUBSTRING;
932 if (o[i] == 'A') op |= ASL_QUERY_OP_PREFIX;
933 if (o[i] == 'Z') op |= ASL_QUERY_OP_SUFFIX;
934 if (o[i] == '<') op |= ASL_QUERY_OP_LESS;
935 if (o[i] == '>') op |= ASL_QUERY_OP_GREATER;
936 if (o[i] == '=') op |= ASL_QUERY_OP_EQUAL;
937 if (o[i] == '!') op |= ASL_QUERY_OP_NOT_EQUAL;
938 if (o[i] == 'T') op |= ASL_QUERY_OP_TRUE;
939 }
940
941 return op;
942 }
943
944 static char *
945 _asl_msg_get_next_word(char **p, uint32_t *tt, uint32_t spacedel)
946 {
947 char *str, *out, c, oval;
948 uint32_t i, len, n, outlen;
949
950 *tt = TOKEN_NULL;
951
952 if (p == NULL) return NULL;
953 if (*p == NULL) return NULL;
954 if (**p == '\0') return NULL;
955
956 /* skip one space if it's there (word separator) */
957 if (**p == ' ') (*p)++;
958
959 /* skip leading white space */
960 if (spacedel != 0)
961 {
962 while ((**p == ' ') || (**p == '\t')) (*p)++;
963 }
964
965 if (**p == '\0') return NULL;
966 if (**p == '\n') return NULL;
967
968 str = *p;
969
970 /* opening [ */
971 if (**p == '[')
972 {
973 *tt = TOKEN_OPEN;
974
975 (*p)++;
976 out = malloc(2);
977 if (out == NULL) return NULL;
978
979 out[0] = '[';
980 out[1] = '\0';
981 return out;
982 }
983
984 /* scan for token and calulate it's length (input and decoded output len) */
985 len = 0;
986 outlen = 0;
987
988 forever
989 {
990 c = str[len];
991
992 /* stop scanning when we hit a delimiter */
993 if (((spacedel != 0) && (c == ' ')) || (c == ']') || (c == '\0')) break;
994
995 if (c == '\\')
996 {
997 len++;
998 c = str[len];
999 if ((c == 'a') || (c == 'b') || (c == 't') || (c == 'n') || (c == 'v') || (c == 'f') || (c == 'r') || (c == 's') || (c == '[') || (c == '\\') || (c == ']'))
1000 {
1001 }
1002 else if (c == '^')
1003 {
1004 if (str[++len] == '\0') return NULL;
1005 }
1006 else if (c == 'M')
1007 {
1008 if (str[++len] == '\0') return NULL;
1009 if (str[++len] == '\0') return NULL;
1010 }
1011 else if ((c >= '0') && (c <= '3'))
1012 {
1013 if (str[++len] == '\0') return NULL;
1014 if (str[++len] == '\0') return NULL;
1015 }
1016 else
1017 {
1018 return NULL;
1019 }
1020 }
1021
1022 len++;
1023 outlen++;
1024 }
1025
1026 (*p) += len;
1027
1028 if ((len == 0) && (**p == ']'))
1029 {
1030 *tt = TOKEN_CLOSE;
1031 (*p)++;
1032 out = malloc(2);
1033 if (out == NULL) return NULL;
1034
1035 out[0] = ']';
1036 out[1] = '\0';
1037 return out;
1038 }
1039
1040 *tt = TOKEN_INT;
1041
1042 out = malloc(outlen + 1);
1043 if (out == NULL) return NULL;
1044
1045 n = 0;
1046 for (i = 0; i < len; i++)
1047 {
1048 c = str[i];
1049
1050 if (c == '\\')
1051 {
1052 *tt = TOKEN_WORD;
1053
1054 i++;
1055 c = str[i];
1056 if (c == 'a')
1057 {
1058 out[n++] = '\a';
1059 }
1060 else if (c == 'b')
1061 {
1062 out[n++] = '\b';
1063 }
1064 else if (c == 't')
1065 {
1066 out[n++] = '\t';
1067 }
1068 else if (c == 'n')
1069 {
1070 out[n++] = '\n';
1071 }
1072 else if (c == 'v')
1073 {
1074 out[n++] = '\v';
1075 }
1076 else if (c == 'f')
1077 {
1078 out[n++] = '\f';
1079 }
1080 else if (c == 'r')
1081 {
1082 out[n++] = '\r';
1083 }
1084 else if (c == 's')
1085 {
1086 out[n++] = ' ';
1087 }
1088 else if (c == '[')
1089 {
1090 out[n++] = '[';
1091 }
1092 else if (c == '\\')
1093 {
1094 out[n++] = '\\';
1095 }
1096 else if (c == ']')
1097 {
1098 out[n++] = ']';
1099 }
1100 else if (c == '^')
1101 {
1102 i++;
1103 if (str[i] == '?') out[n++] = 127;
1104 else out[n++] = str[i] - 64;
1105 }
1106 else if (c == 'M')
1107 {
1108 i++;
1109 c = str[i];
1110 if (c == '^')
1111 {
1112 i++;
1113 if (str[i] == '?') out[n++] = 255;
1114 else out[n++] = str[i] + 64;
1115 }
1116 else if (c == '-')
1117 {
1118 i++;
1119 out[n++] = str[i] + 128;
1120 }
1121 else
1122 {
1123 *tt = TOKEN_NULL;
1124 free(out);
1125 return NULL;
1126 }
1127
1128 }
1129 else if ((c >= '0') && (c <= '3'))
1130 {
1131 oval = (c - '0') * 64;
1132
1133 i++;
1134 c = str[i];
1135 if ((c < '0') || (c > '7'))
1136 {
1137 *tt = TOKEN_NULL;
1138 free(out);
1139 return NULL;
1140 }
1141
1142 oval += ((c - '0') * 8);
1143
1144 i++;
1145 c = str[i];
1146 if ((c < '0') || (c > '7'))
1147 {
1148 *tt = TOKEN_NULL;
1149 free(out);
1150 return NULL;
1151 }
1152
1153 oval += (c - '0');
1154
1155 out[n++] = oval;
1156 }
1157 else
1158 {
1159 *tt = TOKEN_NULL;
1160 free(out);
1161 return NULL;
1162 }
1163 }
1164 else
1165 {
1166
1167 if ((c < '0') || (c > '9')) *tt = TOKEN_WORD;
1168 out[n++] = c;
1169 }
1170 }
1171
1172 out[n] = '\0';
1173
1174 return out;
1175 }
1176
1177 asl_msg_t *
1178 asl_msg_from_string(const char *buf)
1179 {
1180 uint32_t tt, type, op;
1181 char *k, *v, *o, *p;
1182 asl_msg_t *msg;
1183
1184 if (buf == NULL) return NULL;
1185
1186 type = ASL_TYPE_MSG;
1187 p = (char *)buf;
1188
1189 k = _asl_msg_get_next_word(&p, &tt, 1);
1190 if (k == NULL) return NULL;
1191
1192 if (streq(k, "Q"))
1193 {
1194 type = ASL_TYPE_QUERY;
1195 free(k);
1196
1197 k = _asl_msg_get_next_word(&p, &tt, 1);
1198 }
1199 else if (tt == TOKEN_INT)
1200 {
1201 /* Leading integer is a string length - skip it */
1202 free(k);
1203 k = _asl_msg_get_next_word(&p, &tt, 1);
1204 if (k == NULL) return NULL;
1205 }
1206
1207 msg = calloc(1, sizeof(asl_msg_t));
1208 if (msg == NULL) return NULL;
1209
1210 msg->type = type;
1211
1212 /* OPEN WORD [WORD [WORD]] CLOSE */
1213 while (k != NULL)
1214 {
1215 op = ASL_QUERY_OP_NULL;
1216
1217 if (tt != TOKEN_OPEN)
1218 {
1219 asl_free(msg);
1220 return NULL;
1221 }
1222
1223 free(k);
1224
1225 /* get op for query type */
1226 if (type == ASL_TYPE_QUERY)
1227 {
1228 o = _asl_msg_get_next_word(&p, &tt, 1);
1229 if ((o == NULL) || (tt != TOKEN_WORD))
1230 {
1231 if (o != NULL) free(o);
1232 asl_free(msg);
1233 return NULL;
1234 }
1235
1236 op = _asl_msg_op_from_string(o);
1237 free(o);
1238 }
1239
1240 k = _asl_msg_get_next_word(&p, &tt, 1);
1241 if (tt == TOKEN_INT) tt = TOKEN_WORD;
1242 if ((k == NULL) || (tt != TOKEN_WORD))
1243 {
1244 if (k != NULL) free(k);
1245 asl_free(msg);
1246 return NULL;
1247 }
1248
1249 v = _asl_msg_get_next_word(&p, &tt, 0);
1250 if (tt == TOKEN_INT) tt = TOKEN_WORD;
1251 if (v == NULL)
1252 {
1253 asl_set_query(msg, k, NULL, op);
1254 break;
1255 }
1256
1257 if (tt == TOKEN_CLOSE)
1258 {
1259 asl_set_query(msg, k, NULL, op);
1260 }
1261 else if (tt == TOKEN_WORD)
1262 {
1263 asl_set_query(msg, k, v, op);
1264 }
1265 else
1266 {
1267 if (k != NULL) free(k);
1268 if (v != NULL) free(v);
1269 asl_free(msg);
1270 return NULL;
1271 }
1272
1273 if (k != NULL) free(k);
1274 if (v != NULL) free(v);
1275
1276 if (tt != TOKEN_CLOSE)
1277 {
1278 k = _asl_msg_get_next_word(&p, &tt, 1);
1279 if (k == NULL) break;
1280
1281 if (tt != TOKEN_CLOSE)
1282 {
1283 asl_free(msg);
1284 return NULL;
1285 }
1286
1287 free(k);
1288 }
1289
1290 k = _asl_msg_get_next_word(&p, &tt, 1);
1291 if (k == NULL) break;
1292 }
1293
1294 return msg;
1295 }
1296
1297 char *
1298 asl_list_to_string(asl_search_result_t *list, uint32_t *outlen)
1299 {
1300 uint32_t i, len, newlen;
1301 char *msgbuf, *out;
1302
1303 if (list == NULL) return NULL;
1304 if (list->count == 0) return NULL;
1305 if (list->msg == NULL) return NULL;
1306
1307 out = NULL;
1308 asprintf(&out, "%u\n", list->count);
1309 if (out == NULL) return NULL;
1310 *outlen = strlen(out) + 1;
1311
1312 for (i = 0; i < list->count; i++)
1313 {
1314 len = 0;
1315 msgbuf = asl_msg_to_string(list->msg[i], &len);
1316 if (msgbuf == NULL)
1317 {
1318 free(out);
1319 *outlen = 0;
1320 return NULL;
1321 }
1322
1323 newlen = *outlen + len;
1324 out = reallocf(out, newlen);
1325 if (out == NULL)
1326 {
1327 *outlen = 0;
1328 return NULL;
1329 }
1330
1331 memmove((out + *outlen - 1), msgbuf, len);
1332 out[newlen - 2] = '\n';
1333 out[newlen - 1] = '\0';
1334 *outlen = newlen;
1335
1336 free(msgbuf);
1337 }
1338
1339 return out;
1340 }
1341
1342 asl_search_result_t *
1343 asl_list_from_string(const char *buf)
1344 {
1345 uint32_t i, n;
1346 const char *p;
1347 asl_search_result_t *out;
1348 asl_msg_t *m;
1349
1350 if (buf == NULL) return NULL;
1351 p = buf;
1352
1353 n = atoi(buf);
1354 if (n == 0) return NULL;
1355
1356 out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
1357 if (out == NULL) return NULL;
1358
1359 out->msg = (asl_msg_t **)calloc(n, sizeof(asl_msg_t *));
1360 if (out->msg == NULL)
1361 {
1362 free(out);
1363 return NULL;
1364 }
1365
1366 for (i = 0; i < n; i++)
1367 {
1368 p = strchr(p, '\n');
1369 if (p == NULL)
1370 {
1371 aslresponse_free((aslresponse)out);
1372 return NULL;
1373 }
1374
1375 p++;
1376
1377 m = asl_msg_from_string(p);
1378 if (m == NULL)
1379 {
1380 aslresponse_free((aslresponse)out);
1381 return NULL;
1382 }
1383
1384 out->msg[i] = m;
1385 out->count += 1;
1386 }
1387
1388 return out;
1389 }
1390
1391 static int
1392 _asl_msg_equal(asl_msg_t *a, asl_msg_t *b)
1393 {
1394 uint32_t i, j;
1395
1396 if (a->count != b->count) return 0;
1397
1398 for (i = 0; i < a->count; i++)
1399 {
1400 j = _asl_msg_index(b, a->key[i]);
1401 if (j == (uint32_t)-1) return 0;
1402
1403 if (a->val[i] == NULL)
1404 {
1405 if (b->val[j] != NULL) return 0;
1406 }
1407 else
1408 {
1409 if (b->val[j] == NULL) return 0;
1410 if (strcmp(a->val[i], b->val[j])) return 0;
1411 }
1412
1413 if (a->type == ASL_TYPE_QUERY)
1414 {
1415 if (a->op[i] != b->op[j]) return 0;
1416 }
1417 }
1418
1419 return 1;
1420 }
1421
1422 static int
1423 _asl_isanumber(char *s)
1424 {
1425 int i;
1426
1427 if (s == NULL) return 0;
1428
1429 i = 0;
1430 if ((s[0] == '-') || (s[0] == '+')) i = 1;
1431
1432 if (s[i] == '\0') return 0;
1433
1434 for (; s[i] != '\0'; i++)
1435 {
1436 if (!isdigit(s[i])) return 0;
1437 }
1438
1439 return 1;
1440 }
1441
1442 static int
1443 _asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
1444 {
1445 int cmp;
1446 uint32_t t;
1447 int nq, nm, rflags;
1448 regex_t rex;
1449
1450 t = op & ASL_QUERY_OP_TRUE;
1451
1452 if (op & ASL_QUERY_OP_REGEX)
1453 {
1454 memset(&rex, 0, sizeof(regex_t));
1455
1456 rflags = REG_EXTENDED | REG_NOSUB;
1457 if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE;
1458
1459 if (regcomp(&rex, q, rflags) != 0) return 0;
1460 cmp = regexec(&rex, m, 0, NULL, 0);
1461 regfree(&rex);
1462 return (cmp == 0);
1463 }
1464
1465 if (op & ASL_QUERY_OP_NUMERIC)
1466 {
1467 /* We assume the query contains a numeric string */
1468 if (_asl_isanumber(m) == 0) return 0;
1469
1470 nq = atoi(q);
1471 nm = atoi(m);
1472
1473 switch (t)
1474 {
1475 case ASL_QUERY_OP_EQUAL: return (nm == nq);
1476 case ASL_QUERY_OP_GREATER: return (nm > nq);
1477 case ASL_QUERY_OP_GREATER_EQUAL: return (nm >= nq);
1478 case ASL_QUERY_OP_LESS: return (nm < nq);
1479 case ASL_QUERY_OP_LESS_EQUAL: return (nm <= nq);
1480 case ASL_QUERY_OP_NOT_EQUAL: return (nm != nq);
1481 default: return 0;
1482 }
1483 }
1484
1485 cmp = 0;
1486 if (op & ASL_QUERY_OP_CASEFOLD)
1487 {
1488 if (n == 0) cmp = strcasecmp(m, q);
1489 else cmp = strncasecmp(m, q, n);
1490 }
1491 else
1492 {
1493 if (n == 0) cmp = strcmp(m, q);
1494 else cmp = strncmp(m, q, n);
1495 }
1496
1497 switch (t)
1498 {
1499 case ASL_QUERY_OP_EQUAL: return (cmp == 0);
1500 case ASL_QUERY_OP_GREATER: return (cmp > 0);
1501 case ASL_QUERY_OP_GREATER_EQUAL: return (cmp >= 0);
1502 case ASL_QUERY_OP_LESS: return (cmp < 0);
1503 case ASL_QUERY_OP_LESS_EQUAL: return (cmp <= 0);
1504 case ASL_QUERY_OP_NOT_EQUAL: return (cmp != 0);
1505 default: return 0;
1506 }
1507
1508 return 0;
1509 }
1510
1511 static int
1512 _asl_msg_test_op_substr(uint32_t op, char *q, char *m)
1513 {
1514 uint32_t i, d, lm, lq;
1515
1516 lm = strlen(m);
1517 lq = strlen(q);
1518
1519 if (lq > lm) return 0;
1520
1521 d = lm - lq;
1522 for (i = 0; i <= d; i++)
1523 {
1524 if (_asl_msg_op_test(op, q, m + i, lq) != 0) return 1;
1525 }
1526
1527 return 0;
1528 }
1529
1530 static int
1531 _asl_msg_test_op_prefix(uint32_t op, char *q, char *m)
1532 {
1533 uint32_t lm, lq;
1534
1535 lm = strlen(m);
1536 lq = strlen(q);
1537
1538 if (lq > lm) return 0;
1539
1540 return _asl_msg_op_test(op, q, m, lq);
1541 }
1542
1543 static int
1544 _asl_msg_test_op_suffix(uint32_t op, char *q, char *m)
1545 {
1546 uint32_t lm, lq, d;
1547
1548 lm = strlen(m);
1549 lq = strlen(q);
1550
1551 if (lq > lm) return 0;
1552
1553 d = lm - lq;
1554 return _asl_msg_op_test(op, q, m + d, lq);
1555 }
1556
1557 static int
1558 _asl_msg_test_op(uint32_t op, char *q, char *m)
1559 {
1560 uint32_t t;
1561
1562 t = op & ASL_QUERY_OP_TRUE;
1563 if (t == ASL_QUERY_OP_TRUE) return 1;
1564
1565 if (op & ASL_QUERY_OP_PREFIX)
1566 {
1567 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_substr(op, q, m);
1568 return _asl_msg_test_op_prefix(op, q, m);
1569 }
1570 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_suffix(op, q, m);
1571
1572 return _asl_msg_op_test(op, q, m, 0);
1573 }
1574
1575 static int
1576 _asl_msg_test_time_op(uint32_t op, char *q, char *m)
1577 {
1578 time_t tq, tm;
1579 char *vq, *vm;
1580 struct tm gtime;
1581 uint32_t t, do_numeric;
1582 int cmp;
1583
1584 do_numeric = 1;
1585
1586 if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX) || (op & ASL_QUERY_OP_CASEFOLD)) do_numeric = 0;
1587
1588 tq = asl_parse_time(q);
1589 if (tq < 0) return _asl_msg_test_op(op, q, m);
1590
1591 tm = asl_parse_time(m);
1592 if (tm < 0) return _asl_msg_test_op(op, q, m);
1593
1594 if (do_numeric == 1)
1595 {
1596 t = op & ASL_QUERY_OP_TRUE;
1597 switch (t)
1598 {
1599 case ASL_QUERY_OP_EQUAL:
1600 if (tm == tq) return 1;
1601 return 0;
1602 case ASL_QUERY_OP_GREATER:
1603 if (tm > tq) return 1;
1604 return 0;
1605 case ASL_QUERY_OP_GREATER_EQUAL:
1606 if (tm >= tq) return 1;
1607 return 0;
1608 case ASL_QUERY_OP_LESS:
1609 if (tm < tq) return 1;
1610 return 0;
1611 case ASL_QUERY_OP_LESS_EQUAL:
1612 if (tm <= tq) return 1;
1613 return 0;
1614 case ASL_QUERY_OP_NOT_EQUAL:
1615 if (tm != tq) return 1;
1616 return 0;
1617 default:
1618 return 0;
1619 }
1620
1621 return 0;
1622 }
1623
1624 memset(&gtime, 0, sizeof(struct tm));
1625 gmtime_r(&tq, &gtime);
1626
1627 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
1628 vq = NULL;
1629 asprintf(&vq, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
1630 if (vq == NULL) return 0;
1631
1632 memset(&gtime, 0, sizeof(struct tm));
1633 gmtime_r(&tm, &gtime);
1634
1635 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
1636 vm = NULL;
1637 asprintf(&vm, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
1638 if (vm == NULL) return 0;
1639
1640 cmp = _asl_msg_test_op(op, q, m);
1641
1642 free(vq);
1643 free(vm);
1644
1645 return cmp;
1646 }
1647
1648 static int
1649 _asl_msg_test(asl_msg_t *q, asl_msg_t *m)
1650 {
1651 uint32_t i, j;
1652 int cmp;
1653 char *val;
1654
1655 for (i = 0; i < q->count; i++)
1656 {
1657 j = _asl_msg_index(m, q->key[i]);
1658 if (j == (uint32_t)-1) return 0;
1659
1660 if (q->val[i] == NULL) continue;
1661 if (q->op == NULL) continue;
1662
1663 if ((q->op[i] & ASL_QUERY_OP_TRUE) == ASL_QUERY_OP_TRUE) continue;
1664
1665 if (m->val[j] == NULL) return 0;
1666
1667 val = q->val[i];
1668
1669 cmp = 1;
1670 if (streq(q->key[i], ASL_KEY_TIME))
1671 {
1672 cmp = _asl_msg_test_time_op(q->op[i], q->val[i], m->val[j]);
1673 }
1674 else
1675 {
1676 cmp = _asl_msg_test_op(q->op[i], val, m->val[j]);
1677 }
1678
1679 if (cmp == 0) return 0;
1680 }
1681
1682 return 1;
1683 }
1684
1685 int
1686 asl_msg_cmp(asl_msg_t *a, asl_msg_t *b)
1687 {
1688 if (a == NULL) return 0;
1689 if (b == NULL) return 0;
1690
1691 if (a->type == b->type) return _asl_msg_equal(a, b);
1692 if (a->type == ASL_TYPE_QUERY) return _asl_msg_test(a, b);
1693 return _asl_msg_test(b, a);
1694 }
1695
1696 /*
1697 * asl_add_file: write log messages to the given file descriptor
1698 * Log messages will be written to this file as well as to the server.
1699 */
1700 int
1701 asl_add_output(aslclient ac, int fd, const char *mfmt, const char *tfmt)
1702 {
1703 uint32_t i;
1704 int use_global_lock;
1705 asl_client_t *asl;
1706
1707 use_global_lock = 0;
1708 asl = (asl_client_t *)ac;
1709 if (asl == NULL)
1710 {
1711 asl = _asl_open_default();
1712 if (asl == NULL) return -1;
1713 pthread_mutex_lock(&_asl_global.lock);
1714 use_global_lock = 1;
1715 }
1716
1717 for (i = 0; i < asl->fd_count; i++)
1718 {
1719 if (asl->fd_list[i] == fd)
1720 {
1721 /* update message format and time format */
1722 if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
1723 asl->fd_mfmt[i] = NULL;
1724 if (mfmt != NULL) asl->fd_mfmt[i] = strdup(mfmt);
1725
1726 if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
1727 asl->fd_tfmt[i] = NULL;
1728 if (tfmt != NULL) asl->fd_tfmt[i] = strdup(tfmt);
1729
1730 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1731 return 0;
1732 }
1733 }
1734
1735 if (asl->fd_count == 0)
1736 {
1737 asl->fd_list = (int *)calloc(1, sizeof(int));
1738 asl->fd_mfmt = (char **)calloc(1, sizeof(char *));
1739 asl->fd_tfmt = (char **)calloc(1, sizeof(char *));
1740 }
1741 else
1742 {
1743 asl->fd_list = (int *)reallocf(asl->fd_list, (1 + asl->fd_count) * sizeof(int));
1744 asl->fd_mfmt = (char **)reallocf(asl->fd_mfmt, (1 + asl->fd_count) * sizeof(char *));
1745 asl->fd_tfmt = (char **)reallocf(asl->fd_tfmt, (1 + asl->fd_count) * sizeof(char *));
1746 }
1747
1748 if ((asl->fd_list == NULL) || (asl->fd_mfmt == NULL) || (asl->fd_tfmt == NULL))
1749 {
1750 if (asl->fd_list != NULL) free(asl->fd_list);
1751 if (asl->fd_mfmt != NULL) free(asl->fd_mfmt);
1752 if (asl->fd_tfmt != NULL) free(asl->fd_tfmt);
1753
1754 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1755 return -1;
1756 }
1757
1758 asl->fd_list[asl->fd_count] = fd;
1759 if (mfmt != NULL) asl->fd_mfmt[asl->fd_count] = strdup(mfmt);
1760 if (tfmt != NULL) asl->fd_tfmt[asl->fd_count] = strdup(tfmt);
1761
1762 asl->fd_count++;
1763
1764 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1765 return 0;
1766 }
1767
1768 int
1769 asl_add_log_file(aslclient ac, int fd)
1770 {
1771 return asl_add_output(ac, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL);
1772 }
1773
1774 /*
1775 * asl_remove_output: stop writing log messages to the given file descriptor
1776 */
1777 int
1778 asl_remove_output(aslclient ac, int fd)
1779 {
1780 uint32_t i;
1781 int x, use_global_lock;
1782 asl_client_t *asl;
1783
1784 use_global_lock = 0;
1785 asl = (asl_client_t *)ac;
1786 if (asl == NULL)
1787 {
1788 asl = _asl_open_default();
1789 if (asl == NULL) return -1;
1790 pthread_mutex_lock(&_asl_global.lock);
1791 use_global_lock = 1;
1792 }
1793
1794 if (asl->fd_count == 0)
1795 {
1796 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1797 return 0;
1798 }
1799
1800 x = -1;
1801 for (i = 0; i < asl->fd_count; i++)
1802 {
1803 if (asl->fd_list[i] == fd)
1804 {
1805 x = i;
1806 break;
1807 }
1808 }
1809
1810 if (x == -1)
1811 {
1812 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1813 return 0;
1814 }
1815
1816 if (asl->fd_mfmt[x] != NULL) free(asl->fd_mfmt[x]);
1817 if (asl->fd_tfmt[x] != NULL) free(asl->fd_tfmt[x]);
1818
1819 for (i = x + 1; i < asl->fd_count; i++, x++)
1820 {
1821 asl->fd_list[x] = asl->fd_list[i];
1822 asl->fd_mfmt[x] = asl->fd_mfmt[i];
1823 asl->fd_tfmt[x] = asl->fd_tfmt[i];
1824 }
1825
1826 asl->fd_count--;
1827
1828 if (asl->fd_count == 0)
1829 {
1830 free(asl->fd_list);
1831 asl->fd_list = NULL;
1832 asl->fd_mfmt = NULL;
1833 asl->fd_tfmt = NULL;
1834 }
1835 else
1836 {
1837 asl->fd_list = (int *)reallocf(asl->fd_list, asl->fd_count * sizeof(int));
1838 asl->fd_mfmt = (char **)reallocf(asl->fd_mfmt, asl->fd_count * sizeof(char *));
1839 asl->fd_tfmt = (char **)reallocf(asl->fd_tfmt, asl->fd_count * sizeof(char *));
1840
1841 if ((asl->fd_list == NULL) || (asl->fd_mfmt == NULL) || (asl->fd_tfmt == NULL))
1842 {
1843 if (asl->fd_list != NULL)
1844 {
1845 free(asl->fd_list);
1846 asl->fd_list = NULL;
1847 }
1848
1849 if (asl->fd_mfmt != NULL)
1850 {
1851 for (i = 0; i < asl->fd_count; i++) if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
1852 free(asl->fd_mfmt);
1853 asl->fd_mfmt = NULL;
1854 }
1855
1856 if (asl->fd_tfmt != NULL)
1857 {
1858 for (i = 0; i < asl->fd_count; i++) if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
1859 free(asl->fd_tfmt);
1860 asl->fd_tfmt = NULL;
1861 }
1862
1863 asl->fd_count = 0;
1864 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1865 return -1;
1866 }
1867 }
1868
1869 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1870 return 0;
1871 }
1872
1873 int
1874 asl_remove_log_file(aslclient ac, int fd)
1875 {
1876 return asl_remove_output(ac, fd);
1877 }
1878
1879 int
1880 asl_set_filter(aslclient ac, int f)
1881 {
1882 int last, use_global_lock;
1883 asl_client_t *asl;
1884
1885 use_global_lock = 0;
1886 asl = (asl_client_t *)ac;
1887 if (asl == NULL)
1888 {
1889 asl = _asl_open_default();
1890 if (asl == NULL) return -1;
1891 pthread_mutex_lock(&_asl_global.lock);
1892 use_global_lock = 1;
1893 }
1894
1895 last = asl->filter;
1896 asl->filter = f;
1897
1898 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1899 return last;
1900 }
1901
1902 /*
1903 * asl_key: examine attribute keys
1904 * returns the key of the nth attribute in a message (beginning at zero)
1905 * returns NULL if the message has fewer attributes
1906 */
1907 const char *
1908 asl_key(aslmsg a, uint32_t n)
1909 {
1910 asl_msg_t *msg;
1911
1912 msg = (asl_msg_t *)a;
1913 if (msg == NULL) return NULL;
1914
1915 if (n >= msg->count) return NULL;
1916 return msg->key[n];
1917 }
1918
1919 /*
1920 * asl_new: create a new log message.
1921 */
1922 aslmsg
1923 asl_new(uint32_t type)
1924 {
1925 uint32_t i;
1926 asl_msg_t *msg;
1927
1928 msg = calloc(1, sizeof(asl_msg_t));
1929 if (msg == NULL) return NULL;
1930
1931 msg->type = type;
1932 if (type == ASL_TYPE_QUERY) return (aslmsg)msg;
1933
1934 /*
1935 * Defaut attributes are:
1936 * 0 Time
1937 * 1 Host
1938 * 2 Sender
1939 * 3 PID
1940 * 4 UID
1941 * 5 GID
1942 * 6 Level
1943 * 7 Message
1944 */
1945 msg->count = 8;
1946
1947 msg->key = calloc(msg->count, sizeof(char *));
1948 if (msg->key == NULL)
1949 {
1950 free(msg);
1951 return NULL;
1952 }
1953
1954 msg->val = calloc(msg->count, sizeof(char *));
1955 if (msg->val == NULL)
1956 {
1957 free(msg->key);
1958 free(msg);
1959 return NULL;
1960 }
1961
1962 i = 0;
1963 msg->key[i] = strdup(ASL_KEY_TIME);
1964 if (msg->key[i] == NULL)
1965 {
1966 asl_free(msg);
1967 return NULL;
1968 }
1969
1970 i++;
1971 msg->key[i] = strdup(ASL_KEY_HOST);
1972 if (msg->key[i] == NULL)
1973 {
1974 asl_free(msg);
1975 return NULL;
1976 }
1977
1978 i++;
1979 msg->key[i] = strdup(ASL_KEY_SENDER);
1980 if (msg->key[i] == NULL)
1981 {
1982 asl_free(msg);
1983 return NULL;
1984 }
1985
1986 i++;
1987 msg->key[i] = strdup(ASL_KEY_PID);
1988 if (msg->key[i] == NULL)
1989 {
1990 asl_free(msg);
1991 return NULL;
1992 }
1993
1994 i++;
1995 msg->key[i] = strdup(ASL_KEY_UID);
1996 if (msg->key[i] == NULL)
1997 {
1998 asl_free(msg);
1999 return NULL;
2000 }
2001
2002 i++;
2003 msg->key[i] = strdup(ASL_KEY_GID);
2004 if (msg->key[i] == NULL)
2005 {
2006 asl_free(msg);
2007 return NULL;
2008 }
2009
2010 i++;
2011 msg->key[i] = strdup(ASL_KEY_LEVEL);
2012 if (msg->key[i] == NULL)
2013 {
2014 asl_free(msg);
2015 return NULL;
2016 }
2017
2018 i++;
2019 msg->key[i] = strdup(ASL_KEY_MSG);
2020 if (msg->key[i] == NULL)
2021 {
2022 asl_free(msg);
2023 return NULL;
2024 }
2025
2026 return (aslmsg)msg;
2027 }
2028
2029 /*
2030 * asl_get: get attribute values from a message
2031 * msg: an aslmsg
2032 * key: attribute key
2033 * returns the attribute value
2034 * returns NULL if the message does not contain the key
2035 */
2036 const char *
2037 asl_get(aslmsg a, const char *key)
2038 {
2039 asl_msg_t *msg;
2040 uint32_t i;
2041
2042 msg = (asl_msg_t *)a;
2043
2044 if (msg == NULL) return NULL;
2045
2046 i = _asl_msg_index(msg, key);
2047 if (i == (uint32_t)-1) return NULL;
2048 return msg->val[i];
2049 }
2050
2051 #endif /* BUILDING_VARIANT */
2052
2053 /*
2054 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
2055 * arguments.
2056 * msg: an aslmsg
2057 * level: the log level of the associated message
2058 * format: A formating string followed by a list of arguments, like vprintf()
2059 * returns 0 for success, non-zero for failure
2060 */
2061 int
2062 asl_vlog(aslclient ac, aslmsg a, int level, const char *format, va_list ap)
2063 {
2064 int status, saved_errno;
2065 asl_msg_t *msg;
2066 char *str, *fmt, *estr;
2067 uint32_t i, len, elen, expand, my_msg;
2068 asl_client_t *asl;
2069
2070 asl = (asl_client_t *)ac;
2071 if (asl == NULL)
2072 {
2073 /*
2074 * Initialize _asl_global so that asl_new will have global data.
2075 * Not strictly necessary, but helps performance.
2076 */
2077 asl = _asl_open_default();
2078 if (asl == NULL) return -1;
2079 }
2080
2081 saved_errno = errno;
2082
2083 if (format == NULL) return -1;
2084
2085 msg = (asl_msg_t *)a;
2086
2087 my_msg = 0;
2088 if (msg == NULL)
2089 {
2090 my_msg = 1;
2091 msg = asl_new(ASL_TYPE_MSG);
2092 if (msg == NULL) return -1;
2093 }
2094
2095 if (msg->type != ASL_TYPE_MSG) return -1;
2096
2097 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
2098 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
2099
2100 str = NULL;
2101 asprintf(&str, "%d", level);
2102 if (str == NULL)
2103 {
2104 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
2105 return -1;
2106 }
2107
2108 asl_set(msg, ASL_KEY_LEVEL, str);
2109 free(str);
2110
2111 /* insert strerror for %m */
2112 len = 0;
2113 elen = 0;
2114 estr = strdup(strerror(saved_errno));
2115 if (estr == NULL)
2116 {
2117 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
2118 return -1;
2119 }
2120
2121 expand = 0;
2122
2123 if (estr != NULL)
2124 {
2125 elen = strlen(estr);
2126
2127 for (i = 0; format[i] != '\0'; i++)
2128 {
2129 if (format[i] == '%')
2130 {
2131 if (format[i+1] == '\0') len++;
2132 else if (format[i+1] == 'm')
2133 {
2134 expand = 1;
2135 len += elen;
2136 i++;
2137 }
2138 else
2139 {
2140 len += 2;
2141 i++;
2142 }
2143 }
2144 else len++;
2145 }
2146 }
2147
2148 fmt = (char *)format;
2149
2150 if (expand != 0)
2151 {
2152 fmt = malloc(len + 1);
2153 if (fmt == NULL)
2154 {
2155 if (estr != NULL) free(estr);
2156 return -1;
2157 }
2158
2159 len = 0;
2160
2161 for (i = 0; format[i] != '\0'; i++)
2162 {
2163 if (format[i] == '%')
2164 {
2165 if (format[i+1] == '\0')
2166 {
2167 }
2168 else if (format[i+1] == 'm')
2169 {
2170 memcpy(fmt+len, estr, elen);
2171 len += elen;
2172 i++;
2173 }
2174 else
2175 {
2176 fmt[len++] = format[i++];
2177 fmt[len++] = format[i];
2178 }
2179 }
2180 else fmt[len++] = format[i];
2181 }
2182
2183 fmt[len] = '\0';
2184 }
2185
2186 if (estr != NULL) free(estr);
2187
2188 vasprintf(&str, fmt, ap);
2189 if (expand != 0) free(fmt);
2190
2191 if (str == NULL)
2192 {
2193 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
2194 return -1;
2195 }
2196
2197 asl_set(msg, ASL_KEY_MSG, str);
2198 free(str);
2199
2200 status = asl_send(ac, (aslmsg)msg);
2201
2202 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
2203 return status;
2204 }
2205
2206 /*
2207 * asl_log: log a message with a particular log level
2208 * msg: an aslmsg
2209 * level: the log level
2210 * format: A formating string followed by a list of arguments, like printf()
2211 * returns 0 for success, non-zero for failure
2212 */
2213 int
2214 asl_log(aslclient ac, aslmsg a, int level, const char *format, ...)
2215 {
2216 va_list ap;
2217 int status;
2218
2219 if (format == NULL) return -1;
2220
2221 va_start(ap, format);
2222 status = asl_vlog(ac, a, level, format, ap);
2223 va_end(ap);
2224
2225 return status;
2226 }
2227
2228 #ifndef BUILDING_VARIANT
2229
2230 static const char *
2231 _asl_level_string(int level)
2232 {
2233 if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG;
2234 if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT;
2235 if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT;
2236 if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR;
2237 if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING;
2238 if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE;
2239 if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO;
2240 if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG;
2241 return "Unknown";
2242 }
2243
2244 /*
2245 * format a message for printing
2246 * out parameter len returns string length including trailing NUL
2247 */
2248 char *
2249 asl_format_message(aslmsg msg, const char *mfmt, const char *tfmt, uint32_t *len)
2250 {
2251 char *out, *tstr, *k, c[2];
2252 const char *hstr, *sstr, *pstr, *mstr, *lstr, *rprc, *rpid, *v;
2253 int i, j, l, mf, tf, paren, oval, level;
2254
2255 out = NULL;
2256 *len = 0;
2257
2258 if (msg == NULL) return NULL;
2259
2260 mf = MFMT_RAW;
2261 tf = TFMT_SEC;
2262
2263 if (mfmt == NULL) mf = MFMT_RAW;
2264 else if (!strcmp(mfmt, ASL_MSG_FMT_RAW)) mf = MFMT_RAW;
2265 else if (!strcmp(mfmt, ASL_MSG_FMT_STD)) mf = MFMT_STD;
2266 else if (!strcmp(mfmt, ASL_MSG_FMT_BSD)) mf = MFMT_BSD;
2267 else if (!strcmp(mfmt, ASL_MSG_FMT_XML)) mf = MFMT_XML;
2268 else if (!strcmp(mfmt, ASL_MSG_FMT_MSG)) mf = MFMT_MSG;
2269 else mf = MFMT_STR;
2270
2271 if (tfmt == NULL) tf = TFMT_SEC;
2272 else if (!strcmp(tfmt, ASL_TIME_FMT_SEC)) tf = TFMT_SEC;
2273 else if (!strcmp(tfmt, ASL_TIME_FMT_UTC)) tf = TFMT_UTC;
2274 else if (!strcmp(tfmt, ASL_TIME_FMT_LCL)) tf = TFMT_LCL;
2275
2276 if (mf == MFMT_RAW)
2277 {
2278 out = _asl_msg_to_string_time_fmt((asl_msg_t *)msg, len, tf);
2279 return out;
2280 }
2281
2282 if (mf == MFMT_MSG)
2283 {
2284 mstr = asl_get(msg, ASL_KEY_MSG);
2285 if (mstr == NULL) return NULL;
2286
2287 _asl_append_string(&out, len, mstr, ENCODE_VIS, 0);
2288 _asl_append_string(&out, len, "\n", ENCODE_NONE, 0);
2289
2290 return out;
2291 }
2292
2293 if ((mf == MFMT_STD) || (mf == MFMT_BSD))
2294 {
2295 /* BSD: Mth dd hh:mm:ss host sender[pid]: message */
2296 /* BSD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]): message */
2297 /* STD: Mth dd hh:mm:ss host sender[pid] <Level>: message */
2298 /* STD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]) <Level>: message */
2299
2300 v = asl_get(msg, ASL_KEY_TIME);
2301 tstr = _asl_time_string(tf, v);
2302
2303 hstr = asl_get(msg, ASL_KEY_HOST);
2304 sstr = asl_get(msg, ASL_KEY_SENDER);
2305 pstr = asl_get(msg, ASL_KEY_PID);
2306 mstr = asl_get(msg, ASL_KEY_MSG);
2307
2308 rprc = asl_get(msg, ASL_KEY_REF_PROC);
2309 rpid = asl_get(msg, ASL_KEY_REF_PID);
2310
2311 level = -1;
2312
2313 if (mf == MFMT_STD)
2314 {
2315 lstr = asl_get(msg, ASL_KEY_LEVEL);
2316 if (lstr != NULL) level = atoi(lstr);
2317 }
2318
2319 if (tstr == NULL)
2320 {
2321 _asl_append_string(&out, len, "0", ENCODE_NONE, 0);
2322 }
2323 else
2324 {
2325 _asl_append_string(&out, len, tstr, ENCODE_NONE, 0);
2326 free(tstr);
2327 }
2328
2329 _asl_append_string(&out, len, " ", ENCODE_NONE, 0);
2330
2331 if (hstr == NULL) _asl_append_string(&out, len, "unknown", ENCODE_NONE, 0);
2332 else _asl_append_string(&out, len, hstr, ENCODE_VIS, 0);
2333
2334 _asl_append_string(&out, len, " ", ENCODE_NONE, 0);
2335
2336 if (sstr == NULL) _asl_append_string(&out, len, "unknown", ENCODE_NONE, 0);
2337 else _asl_append_string(&out, len, sstr, ENCODE_VIS, 0);
2338
2339 if ((pstr != NULL) && (strcmp(pstr, "-1")))
2340 {
2341 _asl_append_string(&out, len, "[", ENCODE_NONE, 0);
2342 _asl_append_string(&out, len, pstr, ENCODE_NONE, 0);
2343 _asl_append_string(&out, len, "]", ENCODE_NONE, 0);
2344 }
2345
2346 if ((rprc != NULL) || (rpid != NULL)) _asl_append_string(&out, len, " (", ENCODE_NONE, 0);
2347
2348 if (rprc != NULL) _asl_append_string(&out, len, rprc, ENCODE_VIS, 0);
2349 if (rpid != NULL)
2350 {
2351 _asl_append_string(&out, len, "[", ENCODE_NONE, 0);
2352 _asl_append_string(&out, len, rpid, ENCODE_NONE, 0);
2353 _asl_append_string(&out, len, "]", ENCODE_NONE, 0);
2354 }
2355
2356 if ((rprc != NULL) || (rpid != NULL)) _asl_append_string(&out, len, ")", ENCODE_NONE, 0);
2357
2358 if (mf == MFMT_STD)
2359 {
2360 _asl_append_string(&out, len, " <", ENCODE_NONE, 0);
2361 _asl_append_string(&out, len, _asl_level_string(level), ENCODE_NONE, 0);
2362 _asl_append_string(&out, len, ">", ENCODE_NONE, 0);
2363 }
2364
2365 _asl_append_string(&out, len, ": ", ENCODE_NONE, 0);
2366
2367 if (mstr != NULL) _asl_append_string(&out, len, mstr, ENCODE_VIS, 0);
2368
2369 _asl_append_string(&out, len, "\n", ENCODE_NONE, 0);
2370 return out;
2371 }
2372
2373 if (mf == MFMT_XML)
2374 {
2375 _asl_append_string(&out, len, "\t<dict>\n", ENCODE_NONE, 0);
2376
2377 for (i = 0; i < msg->count; i++)
2378 {
2379 if (asl_is_utf8(msg->key[i]) == 1)
2380 {
2381 _asl_append_xml_tag(&out, len, XML_TAG_KEY, msg->key[i]);
2382 if (!strcmp(msg->key[i], ASL_KEY_TIME))
2383 {
2384 tstr = _asl_time_string(tf, msg->val[i]);
2385 _asl_append_xml_tag(&out, len, XML_TAG_STRING, tstr);
2386 if (tstr != NULL) free(tstr);
2387 }
2388 else
2389 {
2390 if (asl_is_utf8(msg->val[i]) == 1) _asl_append_xml_tag(&out, len, XML_TAG_STRING, msg->val[i]);
2391 else _asl_append_xml_tag(&out, len, XML_TAG_DATA, msg->val[i]);
2392 }
2393 }
2394 }
2395
2396 _asl_append_string(&out, len, "\t</dict>\n", ENCODE_NONE, 0);
2397
2398 return out;
2399 }
2400
2401 c[1] = '\0';
2402
2403 for (i = 0; mfmt[i] != '\0'; i++)
2404 {
2405 if (mfmt[i] == '$')
2406 {
2407 i++;
2408 paren = 0;
2409
2410 if (mfmt[i] == '(')
2411 {
2412 paren = 1;
2413 i++;
2414 }
2415
2416 k = calloc(1, 1);
2417 if (k == NULL)
2418 {
2419 if (out != NULL) free(out);
2420 return NULL;
2421 }
2422
2423 l = 0;
2424
2425 for (j = i; mfmt[j] != '\0'; j++)
2426 {
2427 c[0] = '\0';
2428 if (mfmt[j] == '\\') c[0] = mfmt[++j];
2429 else if ((paren == 1) && (mfmt[j] ==')')) break;
2430 else if (mfmt[j] != ' ') c[0] = mfmt[j];
2431
2432 if (c[0] == '\0') break;
2433
2434 k = reallocf(k, l + 1);
2435 if (k == NULL)
2436 {
2437 if (out != NULL) free(out);
2438 return NULL;
2439 }
2440
2441 k[l] = c[0];
2442 k[l + 1] = '\0';
2443 l++;
2444 }
2445
2446 if (paren == 1) j++;
2447 i = j;
2448 if (l > 0)
2449 {
2450 v = asl_get(msg, k);
2451 if (v != NULL)
2452 {
2453 if (!strcmp(k, ASL_KEY_TIME))
2454 {
2455 tstr = _asl_time_string(tf, v);
2456 _asl_append_string(&out, len, tstr, ENCODE_NONE, 0);
2457 if (tstr != NULL) free(tstr);
2458 }
2459 else
2460 {
2461 _asl_append_string(&out, len, (char *)v, ENCODE_NONE, 0);
2462 }
2463 }
2464 }
2465 free(k);
2466 }
2467
2468 if (mfmt[i] == '\\')
2469 {
2470 i++;
2471 if (mfmt[i] == '$') _asl_append_string(&out, len, "$", ENCODE_NONE, 0);
2472 else if (mfmt[i] == 'e') _asl_append_string(&out, len, "\e", ENCODE_NONE, 0);
2473 else if (mfmt[i] == 's') _asl_append_string(&out, len, " ", ENCODE_NONE, 0);
2474 else if (mfmt[i] == 'a') _asl_append_string(&out, len, "\a", ENCODE_NONE, 0);
2475 else if (mfmt[i] == 'b') _asl_append_string(&out, len, "\b", ENCODE_NONE, 0);
2476 else if (mfmt[i] == 'f') _asl_append_string(&out, len, "\f", ENCODE_NONE, 0);
2477 else if (mfmt[i] == 'n') _asl_append_string(&out, len, "\n", ENCODE_NONE, 0);
2478 else if (mfmt[i] == 'r') _asl_append_string(&out, len, "\r", ENCODE_NONE, 0);
2479 else if (mfmt[i] == 't') _asl_append_string(&out, len, "\t", ENCODE_NONE, 0);
2480 else if (mfmt[i] == 'v') _asl_append_string(&out, len, "\v", ENCODE_NONE, 0);
2481 else if (mfmt[i] == '\'') _asl_append_string(&out, len, "\'", ENCODE_NONE, 0);
2482 else if (mfmt[i] == '\\') _asl_append_string(&out, len, "\\", ENCODE_NONE, 0);
2483 else if (isdigit(mfmt[i]))
2484 {
2485 oval = mfmt[i] - '0';
2486 if (isdigit(mfmt[i+1]))
2487 {
2488 i++;
2489 oval = (oval * 8) + (mfmt[i] - '0');
2490 if (isdigit(mfmt[i+1]))
2491 {
2492 i++;
2493 oval = (oval * 8) + (mfmt[i] - '0');
2494 }
2495 }
2496 c[0] = oval;
2497 _asl_append_string(&out, len, c, ENCODE_NONE, 0);
2498 }
2499 continue;
2500 }
2501
2502 if (mfmt[i] == '\0') break;
2503 c[0] = mfmt[i];
2504 _asl_append_string(&out, len, c, ENCODE_NONE, 0);
2505 }
2506
2507 _asl_append_string(&out, len, "\n", ENCODE_NONE, 0);
2508
2509 return out;
2510 }
2511
2512 /*
2513 * asl_send: send a message
2514 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
2515 * has been used to set all of a message's attributes.
2516 * msg: an aslmsg
2517 * returns 0 for success, non-zero for failure
2518 */
2519 int
2520 asl_send(aslclient ac, aslmsg msg)
2521 {
2522 char *str, *out_raw, *out;
2523 uint32_t i, len, level, lmask, outstatus, filter, senderx, facilityx;
2524 uint64_t v64;
2525 const char *val;
2526 char *name, *x;
2527 time_t tick;
2528 int status, rc_filter;
2529 asl_client_t *asl;
2530 int use_global_lock;
2531 asl_msg_t *mt;
2532 char hname[_POSIX_HOST_NAME_MAX];
2533
2534 use_global_lock = 0;
2535 asl = (asl_client_t *)ac;
2536 if (asl == NULL)
2537 {
2538 asl = _asl_open_default();
2539 if (asl == NULL) return -1;
2540 use_global_lock = 1;
2541 }
2542
2543 if (msg == NULL) return 0;
2544
2545 level = ASL_LEVEL_DEBUG;
2546
2547 val = asl_get(msg, ASL_KEY_LEVEL);
2548 if (val != NULL) level = atoi(val);
2549
2550 lmask = ASL_FILTER_MASK(level);
2551
2552 filter = asl->filter;
2553 rc_filter = 0;
2554
2555 if (!(asl->options & ASL_OPT_NO_REMOTE))
2556 {
2557 pthread_mutex_lock(&_asl_global.lock);
2558
2559 if (_asl_global.notify_token >= 0)
2560 {
2561 v64 = 0;
2562
2563 status = notify_get_state(_asl_global.notify_token, &v64);
2564 if ((status == NOTIFY_STATUS_OK) && (v64 != 0))
2565 {
2566 filter = v64;
2567 rc_filter = 1;
2568 }
2569 }
2570
2571 if ((rc_filter == 0) && (_asl_global.master_token >= 0))
2572 {
2573 v64 = 0;
2574
2575 status = notify_get_state(_asl_global.master_token, &v64);
2576 if ((status == NOTIFY_STATUS_OK) && (v64 != 0))
2577 {
2578 filter = v64;
2579 }
2580 }
2581
2582 pthread_mutex_unlock(&_asl_global.lock);
2583 }
2584
2585 /*
2586 * Time, Host, PID, UID, and GID values get set here
2587 */
2588 str = NULL;
2589 tick = time(NULL);
2590 asprintf(&str, "%lu", tick);
2591 if (str != NULL)
2592 {
2593 asl_set(msg, ASL_KEY_TIME, str);
2594 free(str);
2595 }
2596
2597 memset(&hname, 0, _POSIX_HOST_NAME_MAX);
2598 if (gethostname(hname, _POSIX_HOST_NAME_MAX) == 0)
2599 {
2600 asl_set(msg, ASL_KEY_HOST, hname);
2601 }
2602
2603 str = NULL;
2604 asprintf(&str, "%u", getpid());
2605 if (str != NULL)
2606 {
2607 asl_set(msg, ASL_KEY_PID, str);
2608 free(str);
2609 }
2610
2611 str = NULL;
2612 asprintf(&str, "%d", getuid());
2613 if (str != NULL)
2614 {
2615 asl_set(msg, ASL_KEY_UID, str);
2616 free(str);
2617 }
2618
2619 str = NULL;
2620 asprintf(&str, "%u", getgid());
2621 if (str != NULL)
2622 {
2623 asl_set(msg, ASL_KEY_GID, str);
2624 free(str);
2625 }
2626
2627 senderx = (uint32_t)-1;
2628 facilityx = (uint32_t)-1;
2629 mt = (asl_msg_t *)msg;
2630
2631 for (i = 0; (i < mt->count) && ((senderx == (uint32_t)-1) || (facilityx == (uint32_t)-1)); i++)
2632 {
2633 if (mt->key[i] == NULL) continue;
2634 if (streq(mt->key[i], ASL_KEY_SENDER)) senderx = i;
2635 else if (streq(mt->key[i], ASL_KEY_FACILITY)) facilityx = i;
2636 }
2637
2638 /*
2639 * Set Sender if needed
2640 */
2641 if ((senderx == (uint32_t)-1) || (mt->val[senderx] == NULL))
2642 {
2643 if ((ac != NULL) && (ac->name != NULL))
2644 {
2645 /* Use the Sender name from the client handle */
2646 asl_set(msg, ASL_KEY_SENDER, ac->name);
2647 }
2648 else
2649 {
2650 /* Get the value for ASL_KEY_SENDER from cache */
2651 if (_asl_global.sender == NULL)
2652 {
2653 name = *(*_NSGetArgv());
2654 if (name != NULL)
2655 {
2656 x = strrchr(name, '/');
2657 if (x != NULL) x++;
2658 else x = name;
2659
2660 pthread_mutex_lock(&_asl_global.lock);
2661
2662 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
2663 pthread_mutex_unlock(&_asl_global.lock);
2664 }
2665 }
2666
2667 if (_asl_global.sender != NULL) asl_set(msg, ASL_KEY_SENDER, _asl_global.sender);
2668 else asl_set(msg, ASL_KEY_SENDER, "Unknown");
2669 }
2670 }
2671
2672 /*
2673 * Set Facility
2674 */
2675 if ((facilityx == (uint32_t)-1) || (mt->val[facilityx] == NULL))
2676 {
2677 if ((ac != NULL) && (ac->facility != NULL))
2678 {
2679 /* Use the Facility name from the client handle */
2680 asl_set(msg, ASL_KEY_FACILITY, ac->facility);
2681 }
2682 }
2683
2684 outstatus = 0;
2685
2686 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
2687
2688 if ((filter != 0) && ((filter & lmask) != 0))
2689 {
2690 len = 0;
2691 out_raw = asl_msg_to_string((asl_msg_t *)msg, &len);
2692
2693 if ((out_raw != NULL) && (len != 0))
2694 {
2695 asprintf(&out, "%10u %s\n", len + 1, out_raw);
2696 if (out != NULL)
2697 {
2698 if (asl->sock == -1) _asl_connect(asl);
2699
2700 if (asl->sock >= 0)
2701 {
2702 status = write(asl->sock, out, len + 12);
2703 if (status < 0)
2704 {
2705 /* Write failed - try resetting */
2706 close(asl->sock);
2707 asl->sock = -1;
2708 _asl_connect(asl);
2709 if (asl->sock >= 0) status = write(asl->sock, out, len + 12);
2710 if (status < 0) outstatus = -1;
2711 }
2712 }
2713 else outstatus = -1;
2714
2715 free(out);
2716 }
2717
2718 free(out_raw);
2719 }
2720 }
2721
2722 for (i = 0; i < asl->fd_count; i++)
2723 {
2724 if (asl->fd_list[i] < 0) continue;
2725
2726 len = 0;
2727 out = asl_format_message(msg, asl->fd_mfmt[i], asl->fd_tfmt[i], &len);
2728 if (out == NULL) continue;
2729
2730 status = write(asl->fd_list[i], out, len - 1);
2731 if (status < 0)
2732 {
2733 asl->fd_list[i] = -1;
2734 outstatus = -1;
2735 }
2736
2737 free(out);
2738 }
2739
2740 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
2741
2742 return outstatus;
2743 }
2744
2745 char *
2746 asl_msg_string(aslmsg a)
2747 {
2748 uint32_t len;
2749
2750 return asl_msg_to_string((asl_msg_t *)a, &len);
2751 }
2752
2753 /*
2754 * asl_free: free a message
2755 * msg: an aslmsg to free
2756 */
2757 void
2758 asl_free(aslmsg a)
2759 {
2760 uint32_t i;
2761 asl_msg_t *msg;
2762
2763 msg = (asl_msg_t *)a;
2764
2765 if (msg == NULL) return;
2766
2767 for (i = 0; i < msg->count; i++)
2768 {
2769 if (msg->key[i] != NULL) free(msg->key[i]);
2770 if (msg->val[i] != NULL) free(msg->val[i]);
2771 }
2772
2773 if (msg->count > 0)
2774 {
2775 if (msg->key != NULL) free(msg->key);
2776 if (msg->val != NULL) free(msg->val);
2777 if (msg->op != NULL) free(msg->op);
2778 }
2779
2780 free(msg);
2781 }
2782
2783 /*
2784 * Called if there's a malloc error while manipulating a message in asl_set_query.
2785 * Cleans up the key, kap, and op fields, sets count to zero.
2786 */
2787 static void
2788 _asl_clear_msg(asl_msg_t *msg)
2789 {
2790 uint32_t i;
2791
2792 if (msg == NULL) return;
2793
2794 for (i = 0; i < msg->count; i++)
2795 {
2796 if (msg->key != NULL && msg->key[i] != NULL) free(msg->key[i]);
2797 if (msg->val != NULL && msg->val[i] != NULL) free(msg->val[i]);
2798 }
2799
2800 if (msg->key != NULL) free(msg->key);
2801 if (msg->val != NULL) free(msg->val);
2802 if (msg->op != NULL) free(msg->op);
2803
2804 msg->key = NULL;
2805 msg->val = NULL;
2806 msg->op = NULL;
2807
2808 msg->count = 0;
2809 }
2810
2811 /*
2812 * asl_set_query: set arbitrary parameters of a query
2813 * Similar to als_set, but allows richer query operations.
2814 * See ASL_QUERY_OP_* above.
2815 * msg: an aslmsg
2816 * key: attribute key
2817 * value: attribute value
2818 * op: an operation from the set above.
2819 * returns 0 for success, non-zero for failure
2820 */
2821 int
2822 asl_set_query(aslmsg a, const char *key, const char *val, uint32_t op)
2823 {
2824 uint32_t i;
2825 char *dk, *dv;
2826 asl_msg_t *msg;
2827
2828 msg = (asl_msg_t *)a;
2829
2830 if (msg == NULL) return 0;
2831
2832 if (key == NULL) return -1;
2833
2834 dv = NULL;
2835
2836 if (streq(key, ASL_KEY_LEVEL))
2837 {
2838 if (val == NULL) return -1;
2839 if (val[0] == '\0') return -1;
2840 if ((val[0] >= '0') && (val[0] <= '9'))
2841 {
2842 i = atoi(val);
2843 asprintf(&dv, "%d", i);
2844 if (dv == NULL) return -1;
2845 }
2846 else if (!strcasecmp(val, ASL_STRING_EMERG))
2847 {
2848 dv = strdup("0");
2849 if (dv == NULL) return -1;
2850 }
2851 else if (!strcasecmp(val, ASL_STRING_ALERT))
2852 {
2853 dv = strdup("1");
2854 if (dv == NULL) return -1;
2855 }
2856 else if (!strcasecmp(val, ASL_STRING_CRIT))
2857 {
2858 dv = strdup("2");
2859 if (dv == NULL) return -1;
2860 }
2861 else if (!strcasecmp(val, ASL_STRING_ERR))
2862 {
2863 dv = strdup("3");
2864 if (dv == NULL) return -1;
2865 }
2866 else if (!strcasecmp(val, ASL_STRING_WARNING))
2867 {
2868 dv = strdup("4");
2869 if (dv == NULL) return -1;
2870 }
2871 else if (!strcasecmp(val, ASL_STRING_NOTICE))
2872 {
2873 dv = strdup("5");
2874 if (dv == NULL) return -1;
2875 }
2876 else if (!strcasecmp(val, ASL_STRING_INFO))
2877 {
2878 dv = strdup("6");
2879 if (dv == NULL) return -1;
2880 }
2881 else if (!strcasecmp(val, ASL_STRING_DEBUG))
2882 {
2883 dv = strdup("7");
2884 if (dv == NULL) return -1;
2885 }
2886 else return -1;
2887 }
2888
2889 if ((dv == NULL) && (val != NULL))
2890 {
2891 dv = strdup(val);
2892 if (dv == NULL) return -1;
2893 }
2894
2895 for (i = 0; i < msg->count; i++)
2896 {
2897 if (msg->key[i] == NULL) continue;
2898
2899 if ((msg->type != ASL_TYPE_QUERY) && (streq(msg->key[i], key)))
2900 {
2901 if (msg->val[i] != NULL) free(msg->val[i]);
2902 msg->val[i] = NULL;
2903 if (val != NULL) msg->val[i] = dv;
2904 if (msg->op != NULL) msg->op[i] = op;
2905 return 0;
2906 }
2907 }
2908
2909 if (msg->count == 0)
2910 {
2911 msg->key = (char **)calloc(1, sizeof(char *));
2912 if (msg->key == NULL)
2913 {
2914 _asl_clear_msg(msg);
2915 return -1;
2916 }
2917
2918 msg->val = (char **)calloc(1, sizeof(char *));
2919 if (msg->val == NULL)
2920 {
2921 _asl_clear_msg(msg);
2922 return -1;
2923 }
2924
2925 if (msg->type == ASL_TYPE_QUERY)
2926 {
2927 msg->op = (uint32_t *)calloc(1, sizeof(uint32_t));
2928 if (msg->op == NULL)
2929 {
2930 _asl_clear_msg(msg);
2931 return -1;
2932 }
2933 }
2934 }
2935 else
2936 {
2937 msg->key = (char **)reallocf(msg->key, (msg->count + 1) * sizeof(char *));
2938 if (msg->key == NULL)
2939 {
2940 _asl_clear_msg(msg);
2941 return -1;
2942 }
2943
2944 msg->val = (char **)reallocf(msg->val, (msg->count + 1) * sizeof(char *));
2945 if (msg->val == NULL)
2946 {
2947 _asl_clear_msg(msg);
2948 return -1;
2949 }
2950
2951 if (msg->type == ASL_TYPE_QUERY)
2952 {
2953 msg->op = (uint32_t *)reallocf(msg->op, (msg->count + 1) * sizeof(uint32_t));
2954 if (msg->op == NULL)
2955 {
2956 _asl_clear_msg(msg);
2957 return -1;
2958 }
2959 }
2960 }
2961
2962 dk = strdup(key);
2963 if (dk == NULL) return -1;
2964
2965 msg->key[msg->count] = dk;
2966 msg->val[msg->count] = dv;
2967 if (msg->op != NULL) msg->op[msg->count] = op;
2968 msg->count++;
2969
2970 return 0;
2971 }
2972
2973 /*
2974 * asl_set: set attributes of a message
2975 * msg: an aslmsg
2976 * key: attribute key
2977 * value: attribute value
2978 * returns 0 for success, non-zero for failure
2979 */
2980 int
2981 asl_set(aslmsg msg, const char *key, const char *val)
2982 {
2983 return asl_set_query(msg, key, val, 0);
2984 }
2985
2986 /*
2987 * asl_unset: remove attributes of a message
2988 * msg: an aslmsg
2989 * key: attribute key
2990 * returns 0 for success, non-zero for failure
2991 */
2992 int
2993 asl_unset(aslmsg a, const char *key)
2994 {
2995 uint32_t i, j;
2996 asl_msg_t *msg;
2997
2998 msg = (asl_msg_t *)a;
2999
3000 if (msg == NULL) return 0;
3001 if (key == NULL) return 0;
3002
3003 for (i = 0; i < msg->count; i++)
3004 {
3005 if (msg->key[i] == NULL) continue;
3006
3007 if (streq(msg->key[i], key))
3008 {
3009 free(msg->key[i]);
3010 if (msg->val[i] != NULL) free(msg->val[i]);
3011
3012 for (j = i + 1; j < msg->count; j++, i++)
3013 {
3014 msg->key[i] = msg->key[j];
3015 msg->val[i] = msg->val[j];
3016 if (msg->op != NULL) msg->op[i] = msg->op[j];
3017 }
3018
3019 msg->count--;
3020
3021 if (msg->count == 0)
3022 {
3023 free(msg->key);
3024 msg->key = NULL;
3025
3026 free(msg->val);
3027 msg->val = NULL;
3028
3029 if (msg->op != NULL) free(msg->op);
3030 msg->op = NULL;
3031 }
3032 else
3033 {
3034 msg->key = (char **)reallocf(msg->key, msg->count * sizeof(char *));
3035 if (msg->key == NULL) return -1;
3036
3037 msg->val = (char **)reallocf(msg->val, msg->count * sizeof(char *));
3038 if (msg->val == NULL) return -1;
3039
3040 if (msg->op != NULL)
3041 {
3042 msg->op = (uint32_t *)reallocf(msg->op, msg->count * sizeof(uint32_t));
3043 if (msg->op == NULL) return -1;
3044 }
3045 }
3046
3047 return 0;
3048 }
3049 }
3050
3051 return 0;
3052 }
3053
3054 /*
3055 * asl_search: Search for messages matching the criteria described
3056 * by the aslmsg. The caller should set the attributes to match using
3057 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
3058 * used for attributes set with asl_set().
3059 * a: an aslmsg
3060 * returns: a set of messages that can be iterated over using aslresp_next(),
3061 * and the values can be retrieved using aslresp_get.
3062 */
3063 aslresponse
3064 asl_search(aslclient ac, aslmsg a)
3065 {
3066 asl_search_result_t *batch, *out;
3067 char *qstr, *str, *res;
3068 uint32_t i, j, len, reslen, status;
3069 uint64_t cmax, qmin;
3070 kern_return_t kstatus;
3071 security_token_t sec;
3072 caddr_t vmstr;
3073
3074 if (a == NULL) return 0;
3075
3076 len = 0;
3077 qstr = asl_msg_to_string((asl_msg_t *)a, &len);
3078
3079 str = NULL;
3080 if (qstr == NULL)
3081 {
3082 asprintf(&str, "0\n");
3083 len = 3;
3084 }
3085 else
3086 {
3087 asprintf(&str, "1\n%s\n", qstr);
3088 len += 4;
3089 free(qstr);
3090 }
3091
3092 if (str == NULL) return NULL;
3093
3094 if (asl_server_port == MACH_PORT_NULL)
3095 {
3096 kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port);
3097 if (kstatus != KERN_SUCCESS) return NULL;
3098 }
3099
3100 /*
3101 * Fetch a batch of results each time through the loop.
3102 * Fetching many small batches rebuces the load on syslogd.
3103 */
3104 out = NULL;
3105 qmin = 0;
3106 cmax = 0;
3107
3108 forever
3109 {
3110 res = NULL;
3111 reslen = 0;
3112 sec.val[0] = -1;
3113 sec.val[1] = -1;
3114 status = 0;
3115
3116 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
3117 if (kstatus != KERN_SUCCESS) return NULL;
3118
3119 memmove(vmstr, str, len);
3120
3121 kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
3122 if (kstatus != KERN_SUCCESS) break;
3123 if (res == NULL) break;
3124
3125 batch = asl_list_from_string(res);
3126 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
3127
3128 if (batch == NULL) break;
3129 if (batch->count == 0)
3130 {
3131 aslresponse_free(batch);
3132 break;
3133 }
3134
3135 if (out == NULL) out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
3136 if (out == NULL)
3137 {
3138 aslresponse_free(batch);
3139 break;
3140 }
3141
3142 if (out->count == 0) out->msg = (asl_msg_t **)calloc(batch->count, sizeof(asl_msg_t *));
3143 else out->msg = (asl_msg_t **)reallocf(out->msg, (out->count + batch->count) * sizeof(asl_msg_t *));
3144 if (out->msg == NULL)
3145 {
3146 aslresponse_free(batch);
3147 free(out);
3148 free(str);
3149 return NULL;
3150 }
3151
3152 for (i = 0, j = out->count; i < batch->count; i++, j++) out->msg[j] = batch->msg[i];
3153
3154 out->count += batch->count;
3155 free(batch->msg);
3156 free(batch);
3157
3158 if (i < FETCH_BATCH) break;
3159
3160 if (cmax > qmin) qmin = cmax;
3161 }
3162
3163 free(str);
3164 return out;
3165 }
3166
3167 /*
3168 * aslresponse_next: Iterate over responses returned from asl_search()
3169 * a: a response returned from asl_search();
3170 * returns: The next log message (an aslmsg) or NULL on failure
3171 */
3172 aslmsg
3173 aslresponse_next(aslresponse r)
3174 {
3175 asl_search_result_t *res;
3176 aslmsg m;
3177
3178 res = (asl_search_result_t *)r;
3179 if (res == NULL) return NULL;
3180
3181 if (res->curr >= res->count) return NULL;
3182 m = res->msg[res->curr];
3183 res->curr++;
3184
3185 return m;
3186 }
3187
3188 /*
3189 * aslresponse_free: Free a response returned from asl_search()
3190 * a: a response returned from asl_search()
3191 */
3192 void
3193 aslresponse_free(aslresponse r)
3194 {
3195 asl_search_result_t *res;
3196 uint32_t i;
3197
3198 res = (asl_search_result_t *)r;
3199 if (res == NULL) return;
3200
3201 for (i = 0; i < res->count; i++) asl_free(res->msg[i]);
3202 free(res->msg);
3203 free(res);
3204 }
3205
3206 int
3207 asl_syslog_faciliy_name_to_num(const char *name)
3208 {
3209 if (name == NULL) return -1;
3210
3211 if (strcaseeq(name, "auth")) return LOG_AUTH;
3212 if (strcaseeq(name, "authpriv")) return LOG_AUTHPRIV;
3213 if (strcaseeq(name, "cron")) return LOG_CRON;
3214 if (strcaseeq(name, "daemon")) return LOG_DAEMON;
3215 if (strcaseeq(name, "ftp")) return LOG_FTP;
3216 if (strcaseeq(name, "install")) return LOG_INSTALL;
3217 if (strcaseeq(name, "kern")) return LOG_KERN;
3218 if (strcaseeq(name, "lpr")) return LOG_LPR;
3219 if (strcaseeq(name, "mail")) return LOG_MAIL;
3220 if (strcaseeq(name, "netinfo")) return LOG_NETINFO;
3221 if (strcaseeq(name, "remoteauth")) return LOG_REMOTEAUTH;
3222 if (strcaseeq(name, "news")) return LOG_NEWS;
3223 if (strcaseeq(name, "security")) return LOG_AUTH;
3224 if (strcaseeq(name, "syslog")) return LOG_SYSLOG;
3225 if (strcaseeq(name, "user")) return LOG_USER;
3226 if (strcaseeq(name, "uucp")) return LOG_UUCP;
3227 if (strcaseeq(name, "local0")) return LOG_LOCAL0;
3228 if (strcaseeq(name, "local1")) return LOG_LOCAL1;
3229 if (strcaseeq(name, "local2")) return LOG_LOCAL2;
3230 if (strcaseeq(name, "local3")) return LOG_LOCAL3;
3231 if (strcaseeq(name, "local4")) return LOG_LOCAL4;
3232 if (strcaseeq(name, "local5")) return LOG_LOCAL5;
3233 if (strcaseeq(name, "local6")) return LOG_LOCAL6;
3234 if (strcaseeq(name, "local7")) return LOG_LOCAL7;
3235 if (strcaseeq(name, "launchd")) return LOG_LAUNCHD;
3236
3237 return -1;
3238 }
3239
3240 const char *
3241 asl_syslog_faciliy_num_to_name(int n)
3242 {
3243 if (n < 0) return NULL;
3244
3245 if (n == LOG_AUTH) return "auth";
3246 if (n == LOG_AUTHPRIV) return "authpriv";
3247 if (n == LOG_CRON) return "cron";
3248 if (n == LOG_DAEMON) return "daemon";
3249 if (n == LOG_FTP) return "ftp";
3250 if (n == LOG_INSTALL) return "install";
3251 if (n == LOG_KERN) return "kern";
3252 if (n == LOG_LPR) return "lpr";
3253 if (n == LOG_MAIL) return "mail";
3254 if (n == LOG_NETINFO) return "netinfo";
3255 if (n == LOG_REMOTEAUTH) return "remoteauth";
3256 if (n == LOG_NEWS) return "news";
3257 if (n == LOG_AUTH) return "security";
3258 if (n == LOG_SYSLOG) return "syslog";
3259 if (n == LOG_USER) return "user";
3260 if (n == LOG_UUCP) return "uucp";
3261 if (n == LOG_LOCAL0) return "local0";
3262 if (n == LOG_LOCAL1) return "local1";
3263 if (n == LOG_LOCAL2) return "local2";
3264 if (n == LOG_LOCAL3) return "local3";
3265 if (n == LOG_LOCAL4) return "local4";
3266 if (n == LOG_LOCAL5) return "local5";
3267 if (n == LOG_LOCAL6) return "local6";
3268 if (n == LOG_LOCAL7) return "local7";
3269 if (n == LOG_LAUNCHD) return "launchd";
3270
3271 return NULL;
3272 }
3273
3274 /*
3275 * utility for converting a time string into a time_t
3276 * we only deal with the following formats:
3277 * Canonical form YYYY.MM.DD hh:mm:ss UTC
3278 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
3279 * absolute form - # seconds since the epoch (e.g. 1095789191)
3280 * relative time - seconds before or after now (e.g. -300, +43200)
3281 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
3282 */
3283
3284 #define CANONICAL_TIME_REX "^[0-9][0-9][0-9][0-9].[01]?[0-9].[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9][ ]+UTC$"
3285 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
3286 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
3287 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
3288
3289 #define SECONDS_PER_MINUTE 60
3290 #define SECONDS_PER_HOUR 3600
3291 #define SECONDS_PER_DAY 86400
3292 #define SECONDS_PER_WEEK 604800
3293
3294 /*
3295 * We use the last letter in the month name to determine
3296 * the month number (0-11). There are two collisions:
3297 * Jan and Jun both end in n
3298 * Mar and Apr both end in r
3299 * In these cases we check the second letter.
3300 *
3301 * The MTH_LAST array maps the last letter to a number.
3302 */
3303 static const int8_t MTH_LAST[] = {-1, 1, 11, -1, -1, -1, 7, -1, -1, -1, -1, 6, -1, 5, -1, 8, -1, 3, -1, 9, -1, 10, -1, -1, 4, -1};
3304
3305 static int
3306 _month_num(char *s)
3307 {
3308 int i;
3309 int8_t v8;
3310
3311 v8 = -1;
3312 if (s[2] > 90) v8 = s[2] - 'a';
3313 else v8 = s[2] - 'A';
3314
3315 if ((v8 < 0) || (v8 > 25)) return -1;
3316
3317 v8 = MTH_LAST[v8];
3318 if (v8 < 0) return -1;
3319
3320 i = v8;
3321 if ((i == 5) && ((s[1] == 'a') || (s[1] == 'A'))) return 0;
3322 if ((i == 3) && ((s[1] == 'a') || (s[1] == 'A'))) return 2;
3323 return i;
3324 }
3325
3326 time_t
3327 asl_parse_time(const char *in)
3328 {
3329 int len, y, status, rflags;
3330 struct tm t;
3331 time_t tick, delta, factor;
3332 char *str, *p, *x;
3333 static regex_t rex_canon, rex_ctime, rex_abs, rex_rel;
3334 static int init_canon = 0;
3335 static int init_ctime = 0;
3336 static int init_abs = 0;
3337 static int init_rel = 0;
3338
3339 if (in == NULL) return -1;
3340
3341 rflags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
3342
3343 if (init_canon == 0)
3344 {
3345 memset(&rex_canon, 0, sizeof(regex_t));
3346 status = regcomp(&rex_canon, CANONICAL_TIME_REX, rflags);
3347 if (status != 0) return -1;
3348 init_canon = 1;
3349 }
3350
3351 if (init_ctime == 0)
3352 {
3353 memset(&rex_ctime, 0, sizeof(regex_t));
3354 status = regcomp(&rex_ctime, CTIME_REX, rflags);
3355 if (status != 0) return -1;
3356 init_ctime = 1;
3357 }
3358
3359 if (init_abs == 0)
3360 {
3361 memset(&rex_abs, 0, sizeof(regex_t));
3362 status = regcomp(&rex_abs, ABSOLUTE_TIME_REX, rflags);
3363 if (status != 0) return -1;
3364 init_abs = 1;
3365 }
3366
3367 if (init_rel == 0)
3368 {
3369 memset(&rex_rel, 0, sizeof(regex_t));
3370 status = regcomp(&rex_rel, RELATIVE_TIME_REX, rflags);
3371 if (status != 0) return -1;
3372 init_rel = 1;
3373 }
3374
3375 len = strlen(in) + 1;
3376
3377 if (regexec(&rex_abs, in, 0, NULL, 0) == 0)
3378 {
3379 /*
3380 * Absolute time (number of seconds since the epoch)
3381 */
3382 str = strdup(in);
3383 if (str == NULL) return -1;
3384
3385 if ((str[len-2] == 's') || (str[len-2] == 'S')) str[len-2] = '\0';
3386
3387 tick = atol(str);
3388 free(str);
3389
3390 return tick;
3391 }
3392 else if (regexec(&rex_rel, in, 0, NULL, 0) == 0)
3393 {
3394 /*
3395 * Reletive time (number of seconds before or after right now)
3396 */
3397 str = strdup(in);
3398 if (str == NULL) return -1;
3399
3400 factor = 1;
3401
3402 if ((str[len-2] == 's') || (str[len-2] == 'S'))
3403 {
3404 str[len-2] = '\0';
3405 }
3406 else if ((str[len-2] == 'm') || (str[len-2] == 'M'))
3407 {
3408 str[len-2] = '\0';
3409 factor = SECONDS_PER_MINUTE;
3410 }
3411 else if ((str[len-2] == 'h') || (str[len-2] == 'H'))
3412 {
3413 str[len-2] = '\0';
3414 factor = SECONDS_PER_HOUR;
3415 }
3416 else if ((str[len-2] == 'd') || (str[len-2] == 'D'))
3417 {
3418 str[len-2] = '\0';
3419 factor = SECONDS_PER_DAY;
3420 }
3421 else if ((str[len-2] == 'w') || (str[len-2] == 'W'))
3422 {
3423 str[len-2] = '\0';
3424 factor = SECONDS_PER_WEEK;
3425 }
3426
3427 tick = time(NULL);
3428 delta = factor * atol(str);
3429 tick += delta;
3430
3431 free(str);
3432
3433 return tick;
3434 }
3435 else if (regexec(&rex_canon, in, 0, NULL, 0) == 0)
3436 {
3437 memset(&t, 0, sizeof(struct tm));
3438 str = strdup(in);
3439 if (str == NULL) return -1;
3440
3441 /* Get year */
3442 x = str;
3443 p = strchr(x, '.');
3444 *p = '\0';
3445 t.tm_year = atoi(x) - 1900;
3446
3447 /* Get month */
3448 x = p + 1;
3449 p = strchr(x, '.');
3450 *p = '\0';
3451 t.tm_mon = atoi(x) - 1;
3452
3453 /* Get day */
3454 x = p + 1;
3455 p = strchr(x, ' ');
3456 *p = '\0';
3457 t.tm_mday = atoi(x);
3458
3459 /* Get hour */
3460 for (x = p + 1; *x == ' '; x++);
3461 p = strchr(x, ':');
3462 *p = '\0';
3463 t.tm_hour = atoi(x);
3464
3465 /* Get minutes */
3466 x = p + 1;
3467 p = strchr(x, ':');
3468 *p = '\0';
3469 t.tm_min = atoi(x);
3470
3471 /* Get seconds */
3472 x = p + 1;
3473 p = strchr(x, ' ');
3474 *p = '\0';
3475 t.tm_sec = atoi(x);
3476
3477 free(str);
3478 return timegm(&t);
3479 }
3480 else if (regexec(&rex_ctime, in, 0, NULL, 0) == 0)
3481 {
3482 /* We assume it's in the current year */
3483 memset(&t, 0, sizeof(struct tm));
3484 tick = time(NULL);
3485 gmtime_r(&tick, &t);
3486 y = t.tm_year;
3487
3488 memset(&t, 0, sizeof(struct tm));
3489 str = strdup(in);
3490 if (str == NULL) return -1;
3491
3492 t.tm_year = y;
3493 t.tm_mon = _month_num(str);
3494 if (t.tm_mon < 0) return -1;
3495
3496 for (x = strchr(str, ' '); *x == ' '; x++);
3497 p = strchr(x, ' ');
3498 *p = '\0';
3499 t.tm_mday = atoi(x);
3500
3501 /* Get hour */
3502 for (x = p + 1; *x == ' '; x++);
3503 p = strchr(x, ':');
3504 *p = '\0';
3505 t.tm_hour = atoi(x);
3506
3507 /* Get minutes */
3508 x = p + 1;
3509 p = strchr(x, ':');
3510 *p = '\0';
3511 t.tm_min = atoi(x);
3512
3513 /* Get seconds */
3514 x = p + 1;
3515 t.tm_sec = atoi(x);
3516
3517 t.tm_isdst = -1;
3518
3519 free(str);
3520 return mktime(&t);
3521 }
3522
3523 return -1;
3524 }
3525
3526 #ifdef ASL_SYSLOG_COMPAT
3527
3528 __private_extern__ void
3529 asl_syslog_syslog(int pri, const char *fmt, ...)
3530 {
3531 va_list ap;
3532 asl_msg_t *m;
3533
3534 if (fmt == NULL) return;
3535
3536 m = asl_new(ASL_TYPE_MSG);
3537
3538 va_start(ap, fmt);
3539 asl_vlog(NULL, m, pri, fmt, ap);
3540 va_end(ap);
3541
3542 asl_free(m);
3543 }
3544
3545 __private_extern__ void
3546 asl_syslog_vsyslog(int pri, const char *fmt, va_list ap)
3547 {
3548 asl_msg_t *m;
3549
3550 m = asl_new(ASL_TYPE_MSG);
3551 asl_vlog(NULL, m, pri, fmt, ap);
3552 asl_free(m);
3553 }
3554
3555 __private_extern__ void
3556 asl_syslog_openlog(const char *ident, int flags, int facility)
3557 {
3558 const char *fname;
3559 uint32_t opts;
3560
3561 opts = 0;
3562
3563 if (flags & LOG_NDELAY) opts |= ASL_OPT_NO_DELAY;
3564 if (flags & LOG_PERROR) opts |= ASL_OPT_STDERR;
3565
3566 fname = asl_syslog_faciliy_num_to_name(facility);
3567 if (fname == NULL) fname = "user";
3568
3569 asl_global_client = asl_open(ident, fname, opts);
3570 }
3571
3572 __private_extern__ void
3573 asl_syslog_closelog()
3574 {
3575 asl_close();
3576 }
3577
3578 __private_extern__ int
3579 asl_syslog_setlogmask(int p)
3580 {
3581 return asl_set_filter(p);
3582 }
3583
3584 #endif ASL_SYSLOG_COMPAT
3585
3586 #endif /* BUILDING_VARIANT */