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