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