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