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