]> git.saurik.com Git - apple/libc.git/blame - gen/asl.c
Libc-391.5.22.tar.gz
[apple/libc.git] / gen / asl.c
CommitLineData
3d9156a7
A
1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <stdarg.h>
31#include <syslog.h>
32#include <errno.h>
33#include <time.h>
34#include <crt_externs.h>
35#include <asl.h>
36#include <asl_private.h>
37#include <regex.h>
38#include <notify.h>
39#include <mach/mach.h>
40#include <pthread.h>
41
42#define _PATH_ASL_IN "/var/run/asl_input"
43
44#define streq(A, B) (strcmp(A, B) == 0)
45#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
46
47#define forever for(;;)
48
49#define TOKEN_NULL 0
50#define TOKEN_OPEN 1
51#define TOKEN_CLOSE 2
52#define TOKEN_WORD 3
53#define TOKEN_INT 4
54
55/* forward */
56time_t asl_parse_time(const char *);
57const char *asl_syslog_faciliy_num_to_name(int n);
58__private_extern__ asl_client_t *_asl_open_default();
59
60/* notify SPI */
61uint32_t notify_get_state(int token, int *state);
62uint32_t notify_register_plain(const char *name, int *out_token);
63
64typedef struct
65{
66 int notify_count;
67 int notify_token;
68 int master_token;
69 char *sender;
70 pthread_mutex_t lock;
71 asl_client_t *asl;
72} _asl_global_t;
73
74#ifndef BUILDING_VARIANT
75__private_extern__ _asl_global_t _asl_global = {0, -1, -1, NULL, PTHREAD_MUTEX_INITIALIZER, NULL};
76
77static int
78_asl_connect(asl_client_t *asl)
79{
80 uint32_t len, status;
81
82 if (asl->sock >= 0) return 0;
83
84 asl->sock = socket(AF_UNIX, SOCK_STREAM, 0);
85 if (asl->sock < 0) return -1;
86
87 memset(&(asl->server), 0, sizeof(struct sockaddr_un));
88 asl->server.sun_family = AF_UNIX;
89
90 strcpy(asl->server.sun_path, _PATH_ASL_IN);
91 len = sizeof(asl->server.sun_len) + sizeof(asl->server.sun_family) + strlen(asl->server.sun_path) + 1;
92 asl->server.sun_len = strlen(_PATH_ASL_IN) + 1;
93
94 status = connect(asl->sock, (const struct sockaddr *)&(asl->server), len);
95
96 if (status < 0) return -1;
97 return 0;
98}
99
100static int
101_asl_notify_open(int do_lock)
102{
103 char *notify_name;
104 const char *prefix;
105 uint32_t status;
106
107 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
108
109 _asl_global.notify_count++;
110
111 if (_asl_global.notify_token != -1)
112 {
113 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
114 return 0;
115 }
116
117 notify_name = NULL;
118
119 prefix = NOTIFY_PREFIX_USER;
120 if (getuid() == 0) prefix = NOTIFY_PREFIX_SYSTEM;
121
122 if (_asl_global.master_token == -1)
123 {
124 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
125 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
126 }
127
128 asprintf(&notify_name, "%s.%d", prefix, getpid());
129
130 if (notify_name != NULL)
131 {
132 status = notify_register_plain(notify_name, &_asl_global.notify_token);
133 free(notify_name);
134 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
135 }
136
137 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
138
139 if (_asl_global.notify_token == -1) return -1;
140 return 0;
141}
142
143static void
144_asl_notify_close()
145{
146 pthread_mutex_lock(&_asl_global.lock);
147
148 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
149
150 if (_asl_global.notify_count > 0)
151 {
152 pthread_mutex_unlock(&_asl_global.lock);
153 return;
154 }
155
156 if (_asl_global.master_token > 0) notify_cancel(_asl_global.master_token);
157 _asl_global.master_token = -1;
158
159 if (_asl_global.notify_token > 0) notify_cancel(_asl_global.notify_token);
160 _asl_global.notify_token = -1;
161
162 pthread_mutex_unlock(&_asl_global.lock);
163}
164
165aslclient
166asl_open(const char *ident, const char *facility, uint32_t opts)
167{
168 char *name, *x;
169 asl_client_t *asl;
170
171 asl = (asl_client_t *)calloc(1, sizeof(asl_client_t));
172 if (asl == NULL)
173 {
174 errno = ENOMEM;
175 return NULL;
176 }
177
178 asl->options = opts;
179
180 asl->sock = -1;
181
182 if (asl->options & ASL_OPT_NO_DELAY)
183 {
184 if (_asl_connect(asl) < 0)
185 {
186 free(asl);
187 return NULL;
188 }
189 }
190
191 asl->pid = getpid();
192 asl->uid = getuid();
193 asl->gid = getgid();
194
195 asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
196
197 if (ident != NULL)
198 {
199 asl->name = strdup(ident);
200 }
201 else
202 {
203 name = *(*_NSGetArgv());
204 if (name != NULL)
205 {
206 x = strrchr(name, '/');
207 if (x != NULL) x++;
208 else x = name;
209 asl->name = strdup(x);
210 }
211 }
212
213 if (facility != NULL) asl->facility = strdup(facility);
214 else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER));
215
216 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
217
218 return (aslclient)asl;
219}
220
221void
222asl_close(aslclient ac)
223{
224 asl_client_t *asl;
225
226 asl = (asl_client_t *)ac;
227 if (asl == NULL) return;
228
229 if (asl->sock >= 0) close(asl->sock);
230 if (asl->name != NULL) free(asl->name);
231 if (asl->facility != NULL) free(asl->facility);
232 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_close();
233 if (asl->fd_list != NULL) free(asl->fd_list);
234
235 memset(asl, 0, sizeof(asl_client_t));
236 free(asl);
237}
238
239__private_extern__ asl_client_t *
240_asl_open_default()
241{
242 pthread_mutex_lock(&_asl_global.lock);
243 if (_asl_global.asl != NULL)
244 {
245 pthread_mutex_unlock(&_asl_global.lock);
246 return _asl_global.asl;
247 }
248
249 /*
250 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
251 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
252 * which locks _asl_global.lock.
253 */
254 _asl_global.asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
255
256 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
257 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
258
259 /* Now call _asl_notify_open(0) to finish the work */
260 _asl_notify_open(0);
261
262 pthread_mutex_unlock(&_asl_global.lock);
263
264 return _asl_global.asl;
265}
266
267static uint32_t
268_asl_msg_index(asl_msg_t *msg, const char *k)
269{
270 uint32_t i;
271
272 if (msg == NULL) return (uint32_t)-1;
273 if (k == NULL) return (uint32_t)-1;
274
275 for (i = 0; i < msg->count; i++)
276 {
277 if (msg->key[i] == NULL) continue;
278 if (streq(msg->key[i], k)) return i;
279 }
280
281 return (uint32_t)-1;
282}
283
284static void
285_asl_append_string(char **m, uint32_t *x, char *s, uint32_t encode, uint32_t escspace)
286{
287 uint32_t i, n;
288
289 if (m == NULL) return;
290 if (x == NULL) return;
291 if (s == NULL) return;
292
293 n = 0;
294 if (encode == 0) n = strlen(s);
295 else
296 {
297 for (i = 0; s[i] != '\0'; i++)
298 {
299 if (s[i] == '\\') n++;
300 else if (s[i] == ']') n++;
301 else if ((escspace != 0) && (s[i] == ' ')) n++;
302 n++;
303 }
304 }
305
306 if (n == 0) return;
307
308 if (*m == NULL)
309 {
310 *m = malloc(n + 1);
311 *x = 1;
312 }
313 else
314 {
315 *m = realloc(*m, n + (*x));
316 }
317
318 if (encode == 0)
319 {
320 memcpy((*m) + (*x) - 1, s, n + 1);
321 *x += n;
322 return;
323 }
324
325 n = *x - 1;
326 for (i = 0; s[i] != '\0'; i++)
327 {
328 if ((s[i] == '\\') || (s[i] == ']') || ((escspace != 0) && (s[i] == ' ')))
329 {
330 (*m)[n++] = '\\';
331 (*m)[n++] = s[i];
332 }
333 else if (s[i] == '\n') (*m)[n++] = ';';
334 else (*m)[n++] = s[i];
335 }
336
337 (*m)[n++] = '\0';
338
339 *x = n;
340
341 return;
342}
343
344static void
345_asl_append_op(char **m, uint32_t *x, uint32_t op)
346{
347 char opstr[8];
348 uint32_t i;
349
350 if (m == NULL) return;
351 if (x == NULL) return;
352
353 if (op == ASL_QUERY_OP_NULL) return _asl_append_string(m, x, ".", 0, 0);
354
355 i = 0;
356 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C';
357
358 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'R';
359
360 if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N';
361
362 if (op & ASL_QUERY_OP_PREFIX)
363 {
364 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S';
365 else opstr[i++] = 'A';
366 }
367 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z';
368
369 switch (op & ASL_QUERY_OP_TRUE)
370 {
371 case ASL_QUERY_OP_EQUAL:
372 opstr[i++] = '=';
373 break;
374 case ASL_QUERY_OP_GREATER:
375 opstr[i++] = '>';
376 break;
377 case ASL_QUERY_OP_GREATER_EQUAL:
378 opstr[i++] = '>';
379 opstr[i++] = '=';
380 break;
381 case ASL_QUERY_OP_LESS:
382 opstr[i++] = '<';
383 break;
384 case ASL_QUERY_OP_LESS_EQUAL:
385 opstr[i++] = '<';
386 opstr[i++] = '=';
387 break;
388 case ASL_QUERY_OP_NOT_EQUAL:
389 opstr[i++] = '!';
390 break;
391 case ASL_QUERY_OP_TRUE:
392 opstr[i++] = 'T';
393 break;
394 default:
395 break;
396 }
397
398 if (i == 0) return _asl_append_string(m, x, ".", 0, 0);
399
400 opstr[i++] = '\0';
401 return _asl_append_string(m, x, opstr, 0, 0);
402}
403
404char *
405asl_msg_to_string(asl_msg_t *msg, uint32_t *len)
406{
407 uint32_t i, outlen;
408 char *out, *s;
409
410 *len = 0;
411
412 if (msg == NULL) return NULL;
413
414 s = NULL;
415 out = NULL;
416 outlen = 0;
417
418 if (msg->type == ASL_TYPE_QUERY)
419 {
420 _asl_append_string(&out, &outlen, "Q ", 0, 0);
421 if (out == NULL) return NULL;
422 }
423
424 if (msg->count == 0)
425 {
426 if (out == NULL) return NULL;
427 *len = outlen;
428 return out;
429 }
430
431 for (i = 0; i < msg->count; i++)
432 {
433 if (msg->key[i] == NULL) continue;
434
435 if (i > 0) _asl_append_string(&out, &outlen, " [", 0, 0);
436 else _asl_append_string(&out, &outlen, "[", 0, 0);
437
438 if (msg->type == ASL_TYPE_QUERY)
439 {
440 _asl_append_op(&out, &outlen, msg->op[i]);
441 _asl_append_string(&out, &outlen, " ", 0, 0);
442 }
443
444 _asl_append_string(&out, &outlen, msg->key[i], 1, 1);
445
446 if (msg->val[i] != NULL)
447 {
448 _asl_append_string(&out, &outlen, " ", 0, 0);
449 _asl_append_string(&out, &outlen, msg->val[i], 1, 0);
450 }
451
452 _asl_append_string(&out, &outlen, "]", 0, 0);
453 }
454
455 *len = outlen;
456 return out;
457}
458
459static uint32_t
460_asl_msg_op_from_string(char *o)
461{
462 uint32_t op, i;
463
464 op = ASL_QUERY_OP_NULL;
465
466 if (o == NULL) return op;
467
468 for (i = 0; o[i] != '\0'; i++)
469 {
470 if (o[i] == '.') return ASL_QUERY_OP_NULL;
471 if (o[i] == 'C') op |= ASL_QUERY_OP_CASEFOLD;
472 if (o[i] == 'R') op |= ASL_QUERY_OP_CASEFOLD;
473 if (o[i] == 'N') op |= ASL_QUERY_OP_NUMERIC;
474 if (o[i] == 'S') op |= ASL_QUERY_OP_SUBSTRING;
475 if (o[i] == 'A') op |= ASL_QUERY_OP_PREFIX;
476 if (o[i] == 'Z') op |= ASL_QUERY_OP_SUFFIX;
477 if (o[i] == '<') op |= ASL_QUERY_OP_LESS;
478 if (o[i] == '>') op |= ASL_QUERY_OP_GREATER;
479 if (o[i] == '=') op |= ASL_QUERY_OP_EQUAL;
480 if (o[i] == '!') op |= ASL_QUERY_OP_NOT_EQUAL;
481 if (o[i] == 'T') op |= ASL_QUERY_OP_TRUE;
482 }
483
484 return op;
485}
486
487static char *
488_asl_msg_get_next_word(char **p, uint32_t *tt, uint32_t spacedel)
489{
490 char *start, *out;
491 uint32_t i, esc, len, n;
492
493 *tt = TOKEN_NULL;
494
495 if (p == NULL) return NULL;
496 if (*p == NULL) return NULL;
497 if (**p == '\0') return NULL;
498
499 /* skip one space if it's there (word separator) */
500 if (**p == ' ') (*p)++;
501
502 /* skip leading white space */
503 if (spacedel != 0)
504 {
505 while ((**p == ' ') || (**p == '\t')) (*p)++;
506 }
507
508 if (**p == '\0') return NULL;
509 if (**p == '\n') return NULL;
510
511 /* opening [ */
512 if (**p == '[')
513 {
514 *tt = TOKEN_OPEN;
515
516 (*p)++;
517 out = malloc(2);
518 out[0] = '[';
519 out[1] = '\0';
520 return out;
521 }
522
523 start = *p;
524 len = 0;
525
526 forever
527 {
528 /* stop scanning when we hit a delimiter */
529 if (((spacedel != 0) && (**p == ' ')) || (**p == ']') || (**p == '\0')) break;
530
531 esc = 0;
532 if (**p == '\\') esc = 1;
533 (*p)++;
534
535 /* skip over escaped chars so len is correct */
536 if ((esc == 1) && ((**p == ' ') || (**p == ']') || (**p == '\\'))) (*p)++;
537 len++;
538 }
539
540 if ((len == 0) && (**p == ']'))
541 {
542 *tt = TOKEN_CLOSE;
543 (*p)++;
544 out = malloc(2);
545 out[0] = ']';
546 out[1] = '\0';
547 return out;
548 }
549
550 *tt = TOKEN_INT;
551
552 out = malloc(len + 1);
553
554 for (n = 0, i = 0; n < len; i++)
555 {
556 if ((start[i] == '\\') && ((start[i+1] == ' ') || (start[i+1] == ']') || (start[i+1] == '\\')))
557 {
558 *tt = TOKEN_WORD;
559 i++;
560 }
561
562 if ((start[i] < '0') || (start[i] > '9')) *tt = TOKEN_WORD;
563 out[n++] = start[i];
564 }
565
566 out[n] = '\0';
567
568 return out;
569}
570
571asl_msg_t *
572asl_msg_from_string(const char *buf)
573{
574 uint32_t tt, type, op;
575 char *k, *v, *o, *p;
576 asl_msg_t *msg;
577
578 if (buf == NULL) return NULL;
579
580 type = ASL_TYPE_MSG;
581 p = (char *)buf;
582
583 k = _asl_msg_get_next_word(&p, &tt, 1);
584 if (k == NULL) return NULL;
585
586 if (streq(k, "Q"))
587 {
588 type = ASL_TYPE_QUERY;
589 free(k);
590
591 k = _asl_msg_get_next_word(&p, &tt, 1);
592 }
593 else if (tt == TOKEN_INT)
594 {
595 /* Leading integer is a string length - skip it */
596 free(k);
597 k = _asl_msg_get_next_word(&p, &tt, 1);
598 if (k == NULL) return NULL;
599 }
600
601 msg = calloc(1, sizeof(asl_msg_t));
602 if (msg == NULL) return NULL;
603 msg->type = type;
604
605 /* OPEN WORD [WORD [WORD]] CLOSE */
606 while (k != NULL)
607 {
608 op = ASL_QUERY_OP_NULL;
609
610 if (tt != TOKEN_OPEN)
611 {
612 asl_free(msg);
613 return NULL;
614 }
615
616 free(k);
617
618 /* get op for query type */
619 if (type == ASL_TYPE_QUERY)
620 {
621 o = _asl_msg_get_next_word(&p, &tt, 1);
622 if ((o == NULL) || (tt != TOKEN_WORD))
623 {
624 if (o != NULL) free(o);
625 asl_free(msg);
626 return NULL;
627 }
628
629 op = _asl_msg_op_from_string(o);
630 free(o);
631 }
632
633 k = _asl_msg_get_next_word(&p, &tt, 1);
634 if (tt == TOKEN_INT) tt = TOKEN_WORD;
635 if ((k == NULL) || (tt != TOKEN_WORD))
636 {
637 if (k != NULL) free(k);
638 asl_free(msg);
639 return NULL;
640 }
641
642 v = _asl_msg_get_next_word(&p, &tt, 0);
643 if (tt == TOKEN_INT) tt = TOKEN_WORD;
644 if (v == NULL)
645 {
646 asl_set_query(msg, k, NULL, op);
647 break;
648 }
649
650 if (tt == TOKEN_CLOSE)
651 {
652 asl_set_query(msg, k, NULL, op);
653 }
654 else if (tt == TOKEN_WORD)
655 {
656 asl_set_query(msg, k, v, op);
657 }
658 else
659 {
660 if (k != NULL) free(k);
661 if (v != NULL) free(v);
662 asl_free(msg);
663 return NULL;
664 }
665
666 if (k != NULL) free(k);
667 if (v != NULL) free(v);
668
669 if (tt != TOKEN_CLOSE)
670 {
671 k = _asl_msg_get_next_word(&p, &tt, 1);
672 if (k == NULL) break;
673
674 if (tt != TOKEN_CLOSE)
675 {
676 asl_free(msg);
677 return NULL;
678 }
679
680 free(k);
681 }
682
683 k = _asl_msg_get_next_word(&p, &tt, 1);
684 if (k == NULL) break;
685 }
686
687 return msg;
688}
689
690static int
691_asl_msg_equal(asl_msg_t *a, asl_msg_t *b)
692{
693 uint32_t i, j;
694
695 if (a->count != b->count) return 0;
696
697 for (i = 0; i < a->count; i++)
698 {
699 j = _asl_msg_index(b, a->key[i]);
700 if (j == (uint32_t)-1) return 0;
701
702 if (a->val[i] == NULL)
703 {
704 if (b->val[j] != NULL) return 0;
705 }
706 else
707 {
708 if (b->val[j] == NULL) return 0;
709 if (strcmp(a->val[i], b->val[j])) return 0;
710 }
711
712 if (a->type == ASL_TYPE_QUERY)
713 {
714 if (a->op[i] != b->op[j]) return 0;
715 }
716 }
717
718 return 1;
719}
720
721static int
722_asl_isanumber(char *s)
723{
724 int i;
725
726 if (s == NULL) return 0;
727
728 i = 0;
729 if ((s[0] == '-') || (s[0] == '+')) i = 1;
730
731 if (s[i] == '\0') return 0;
732
733 for (; s[i] != '\0'; i++)
734 {
735 if (!isdigit(s[i])) return 0;
736 }
737
738 return 1;
739}
740
741static int
742_asl_msg_op_test(uint32_t op, char *q, char *m, uint32_t n)
743{
744 int cmp;
745 uint32_t t;
746 int nq, nm, rflags;
747 regex_t rex;
748
749 t = op & ASL_QUERY_OP_TRUE;
750
751 if (op & ASL_QUERY_OP_REGEX)
752 {
753 memset(&rex, 0, sizeof(regex_t));
754
755 rflags = REG_EXTENDED | REG_NOSUB;
756 if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE;
757
758 if (regcomp(&rex, q, rflags) != 0) return 0;
759 return (regexec(&rex, m, 0, NULL, 0) == 0);
760 }
761
762 if (op & ASL_QUERY_OP_NUMERIC)
763 {
764 /* We assume the query contains a numeric string */
765 if (_asl_isanumber(m) == 0) return 0;
766
767 nq = atoi(q);
768 nm = atoi(m);
769
770 switch (t)
771 {
772 case ASL_QUERY_OP_EQUAL: return (nm == nq);
773 case ASL_QUERY_OP_GREATER: return (nm > nq);
774 case ASL_QUERY_OP_GREATER_EQUAL: return (nm >= nq);
775 case ASL_QUERY_OP_LESS: return (nm < nq);
776 case ASL_QUERY_OP_LESS_EQUAL: return (nm <= nq);
777 case ASL_QUERY_OP_NOT_EQUAL: return (nm != nq);
778 default: return 0;
779 }
780 }
781
782 cmp = 0;
783 if (op & ASL_QUERY_OP_CASEFOLD)
784 {
785 if (n == 0) cmp = strcasecmp(m, q);
786 else cmp = strncasecmp(m, q, n);
787 }
788 else
789 {
790 if (n == 0) cmp = strcmp(m, q);
791 else cmp = strncmp(m, q, n);
792 }
793
794 switch (t)
795 {
796 case ASL_QUERY_OP_EQUAL: return (cmp == 0);
797 case ASL_QUERY_OP_GREATER: return (cmp > 0);
798 case ASL_QUERY_OP_GREATER_EQUAL: return (cmp >= 0);
799 case ASL_QUERY_OP_LESS: return (cmp < 0);
800 case ASL_QUERY_OP_LESS_EQUAL: return (cmp <= 0);
801 case ASL_QUERY_OP_NOT_EQUAL: return (cmp != 0);
802 default: return 0;
803 }
804
805 return 0;
806}
807
808static int
809_asl_msg_test_op_substr(uint32_t op, char *q, char *m)
810{
811 uint32_t i, d, lm, lq;
812
813 lm = strlen(m);
814 lq = strlen(q);
815
816 if (lq > lm) return 0;
817
818 d = lm - lq;
819 for (i = 0; i < d; i++)
820 {
821 if (_asl_msg_op_test(op, q, m + i, lq) != 0) return 1;
822 }
823
824 return 0;
825}
826
827static int
828_asl_msg_test_op_prefix(uint32_t op, char *q, char *m)
829{
830 uint32_t lm, lq;
831
832 lm = strlen(m);
833 lq = strlen(q);
834
835 if (lq > lm) return 0;
836
837 return _asl_msg_op_test(op, q, m, lq);
838}
839
840static int
841_asl_msg_test_op_suffix(uint32_t op, char *q, char *m)
842{
843 uint32_t lm, lq, d;
844
845 lm = strlen(m);
846 lq = strlen(q);
847
848 if (lq > lm) return 0;
849
850 d = lm - lq;
851 return _asl_msg_op_test(op, q, m + d, lq);
852}
853
854static int
855_asl_msg_test_op(uint32_t op, char *q, char *m)
856{
857 uint32_t t;
858
859 t = op & ASL_QUERY_OP_TRUE;
860 if (t == ASL_QUERY_OP_TRUE) return 1;
861
862 if (op & ASL_QUERY_OP_PREFIX)
863 {
864 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_substr(op, q, m);
865 return _asl_msg_test_op_prefix(op, q, m);
866 }
867 if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_op_suffix(op, q, m);
868
869 return _asl_msg_op_test(op, q, m, 0);
870}
871
872static int
873_asl_msg_test(asl_msg_t *q, asl_msg_t *m)
874{
875 uint32_t i, j;
876 int cmp, freeval;
877 char *val;
878 struct tm gtime;
879 time_t tick;
880
881 for (i = 0; i < q->count; i++)
882 {
883 j = _asl_msg_index(m, q->key[i]);
884 if (j == (uint32_t)-1) return 0;
885
886 if (q->val[i] == NULL) continue;
887 if ((q->op[i] & ASL_QUERY_OP_TRUE) == ASL_QUERY_OP_TRUE) continue;
888
889 if (m->val[j] == NULL) return 0;
890
891 val = q->val[i];
892 freeval = 0;
893
894 if (streq(q->key[i], ASL_KEY_TIME))
895 {
896 tick = asl_parse_time(val);
897 if (tick != -1)
898 {
899 memset(&gtime, 0, sizeof(struct tm));
900 gmtime_r(&tick, &gtime);
901
902 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
903 val = NULL;
904 asprintf(&val, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
905 freeval = 1; }
906 }
907
908 cmp = _asl_msg_test_op(q->op[i], val, m->val[j]);
909 if ((freeval == 1) && (val != NULL)) free(val);
910
911 if (cmp == 0) return 0;
912 }
913
914 return 1;
915}
916
917int
918asl_msg_cmp(asl_msg_t *a, asl_msg_t *b)
919{
920 if (a == NULL) return 0;
921 if (b == NULL) return 0;
922
923 if (a->type == b->type) return _asl_msg_equal(a, b);
924 if (a->type == ASL_TYPE_QUERY) return _asl_msg_test(a, b);
925 return _asl_msg_test(b, a);
926}
927
928static char *
929_get_line_from_file(FILE *f)
930{
931 char *s, *out;
932 size_t len;
933
934 out = fgetln(f, &len);
935 if (out == NULL) return NULL;
936 if (len == 0) return NULL;
937
938 if (out[len] != '\n') len++;
939
940 s = malloc(len);
941 memcpy(s, out, len - 1);
942
943 s[len] = '\0';
944 return s;
945}
946
947/*
948 * asl_add_file: write log messages to the given file descriptor
949 * Log messages will be written to this file as well as to the server.
950 */
951int
952asl_add_log_file(aslclient ac, int fd)
953{
954 uint32_t i;
955 int use_global_lock;
956 asl_client_t *asl;
957
958 use_global_lock = 0;
959 asl = (asl_client_t *)ac;
960 if (asl == NULL)
961 {
962 asl = _asl_open_default();
963 if (asl == NULL) return -1;
964 pthread_mutex_lock(&_asl_global.lock);
965 use_global_lock = 1;
966 }
967
968 for (i = 0; i < asl->fd_count; i++)
969 {
970 if (asl->fd_list[i] == fd)
971 {
972 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
973 return 0;
974 }
975 }
976
977 if (asl->fd_count == 0)
978 {
979 asl->fd_list = (int *)calloc(1, sizeof(int));
980 }
981 else
982 {
983 asl->fd_list = (int *)realloc(asl->fd_list, (1 + asl->fd_count) * sizeof(int));
984 }
985
986 if (asl->fd_list == NULL)
987 {
988 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
989 return -1;
990 }
991
992 asl->fd_list[asl->fd_count] = fd;
993 asl->fd_count++;
994
995 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
996 return 0;
997}
998
999/*
1000 * asl_remove_file: stop writing log messages to the given file descriptor
1001 */
1002int
1003asl_remove_log_file(aslclient ac, int fd)
1004{
1005 uint32_t i;
1006 int x, use_global_lock;
1007 asl_client_t *asl;
1008
1009 use_global_lock = 0;
1010 asl = (asl_client_t *)ac;
1011 if (asl == NULL)
1012 {
1013 asl = _asl_open_default();
1014 if (asl == NULL) return -1;
1015 pthread_mutex_lock(&_asl_global.lock);
1016 use_global_lock = 1;
1017 }
1018
1019 if (asl->fd_count == 0)
1020 {
1021 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1022 return 0;
1023 }
1024
1025 x = -1;
1026 for (i = 0; i < asl->fd_count; i++)
1027 {
1028 if (asl->fd_list[i] == fd)
1029 {
1030 x = i;
1031 break;
1032 }
1033 }
1034
1035 if (x == -1)
1036 {
1037 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1038 return 0;
1039 }
1040
1041 for (i = x + 1; i < asl->fd_count; i++, x++) asl->fd_list[x] = asl->fd_list[i];
1042 asl->fd_count--;
1043
1044 if (asl->fd_count == 0)
1045 {
1046 free(asl->fd_list);
1047 asl->fd_list = NULL;
1048 }
1049 else
1050 {
1051 asl->fd_list = (int *)realloc(asl->fd_list, asl->fd_count * sizeof(int));
1052 if (asl->fd_list == NULL)
1053 {
1054 asl->fd_count = 0;
1055 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1056 return -1;
1057 }
1058 }
1059
1060 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1061 return 0;
1062}
1063
1064int
1065asl_set_filter(aslclient ac, int f)
1066{
1067 int last, use_global_lock;
1068 asl_client_t *asl;
1069
1070 use_global_lock = 0;
1071 asl = (asl_client_t *)ac;
1072 if (asl == NULL)
1073 {
1074 asl = _asl_open_default();
1075 if (asl == NULL) return -1;
1076 pthread_mutex_lock(&_asl_global.lock);
1077 use_global_lock = 1;
1078 }
1079
1080 last = asl->filter;
1081 asl->filter = f;
1082
1083 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1084 return last;
1085}
1086
1087/*
1088 * asl_key: examine attribute keys
1089 * returns the key of the nth attribute in a message (beginning at zero)
1090 * returns NULL if the message has fewer attributes
1091 */
1092const char *
1093asl_key(aslmsg a, uint32_t n)
1094{
1095 asl_msg_t *msg;
1096
1097 msg = (asl_msg_t *)a;
1098 if (msg == NULL) return NULL;
1099
1100 if (n >= msg->count) return NULL;
1101 return msg->key[n];
1102}
1103
1104/*
1105 * asl_new: create a new log message.
1106 */
1107aslmsg
1108asl_new(uint32_t type)
1109{
1110 uint32_t i;
1111 asl_msg_t *msg;
1112 char *name, *x;
1113
1114 msg = calloc(1, sizeof(asl_msg_t));
1115 if (msg == NULL) return NULL;
1116
1117 msg->type = type;
1118 if (type == ASL_TYPE_QUERY) return (aslmsg)msg;
1119
1120 /*
1121 * Defaut attributes are:
1122 * 0 Time
1123 * 1 Host
1124 * 2 Sender
1125 * 3 PID
1126 * 4 UID
1127 * 5 GID
1128 * 6 Level
1129 * 7 Message
1130 */
1131 msg->count = 8;
1132
1133 msg->key = calloc(msg->count, sizeof(char *));
1134 if (msg->key == NULL)
1135 {
1136 free(msg);
1137 return NULL;
1138 }
1139
1140 msg->val = calloc(msg->count, sizeof(char *));
1141 if (msg->val == NULL)
1142 {
1143 free(msg->key);
1144 free(msg);
1145 return NULL;
1146 }
1147
1148 i = 0;
1149 msg->key[i] = strdup(ASL_KEY_TIME);
1150 if (msg->key[i] == NULL)
1151 {
1152 asl_free(msg);
1153 return NULL;
1154 }
1155
1156 i++;
1157 msg->key[i] = strdup(ASL_KEY_HOST);
1158 if (msg->key[i] == NULL)
1159 {
1160 asl_free(msg);
1161 return NULL;
1162 }
1163
1164 i++;
1165 msg->key[i] = strdup(ASL_KEY_SENDER);
1166 if (msg->key[i] == NULL)
1167 {
1168 asl_free(msg);
1169 return NULL;
1170 }
1171
1172 /* Get the value for ASL_KEY_SENDER from cache */
1173 if (_asl_global.sender == NULL)
1174 {
1175 name = *(*_NSGetArgv());
1176 if (name != NULL)
1177 {
1178 x = strrchr(name, '/');
1179 if (x != NULL) x++;
1180 else x = name;
1181
1182 pthread_mutex_lock(&_asl_global.lock);
1183 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
1184 pthread_mutex_unlock(&_asl_global.lock);
1185 }
1186 }
1187
1188 if (_asl_global.sender == NULL)
1189 {
1190 msg->val[i] = strdup("Unknown");
1191 if (msg->val[i] == NULL)
1192 {
1193 asl_free(msg);
1194 return NULL;
1195 }
1196 }
1197 else
1198 {
1199 msg->val[i] = strdup(_asl_global.sender);
1200 if (msg->val[i] == NULL)
1201 {
1202 asl_free(msg);
1203 return NULL;
1204 }
1205 }
1206
1207 i++;
1208 msg->key[i] = strdup(ASL_KEY_PID);
1209 if (msg->key[i] == NULL)
1210 {
1211 asl_free(msg);
1212 return NULL;
1213 }
1214
1215 i++;
1216 msg->key[i] = strdup(ASL_KEY_UID);
1217 if (msg->key[i] == NULL)
1218 {
1219 asl_free(msg);
1220 return NULL;
1221 }
1222
1223 i++;
1224 msg->key[i] = strdup(ASL_KEY_GID);
1225 if (msg->key[i] == NULL)
1226 {
1227 asl_free(msg);
1228 return NULL;
1229 }
1230
1231 i++;
1232 msg->key[i] = strdup(ASL_KEY_LEVEL);
1233 if (msg->key[i] == NULL)
1234 {
1235 asl_free(msg);
1236 return NULL;
1237 }
1238
1239 i++;
1240 msg->key[i] = strdup(ASL_KEY_MSG);
1241 if (msg->key[i] == NULL)
1242 {
1243 asl_free(msg);
1244 return NULL;
1245 }
1246
1247 return (aslmsg)msg;
1248}
1249
1250/*
1251 * asl_get: get attribute values from a message
1252 * msg: an aslmsg
1253 * key: attribute key
1254 * returns the attribute value
1255 * returns NULL if the message does not contain the key
1256 */
1257const char *
1258asl_get(aslmsg a, const char *key)
1259{
1260 asl_msg_t *msg;
1261 uint32_t i;
1262
1263 msg = (asl_msg_t *)a;
1264
1265 if (msg == NULL) return NULL;
1266
1267 i = _asl_msg_index(msg, key);
1268 if (i == (uint32_t)-1) return NULL;
1269 return msg->val[i];
1270}
1271
1272#endif /* BUILDING_VARIANT */
1273
1274/*
1275 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
1276 * arguments.
1277 * msg: an aslmsg
1278 * level: the log level of the associated message
1279 * format: A formating string followed by a list of arguments, like vprintf()
1280 * returns 0 for success, non-zero for failure
1281 */
1282int
1283asl_vlog(aslclient ac, aslmsg a, int level, const char *format, va_list ap)
1284{
1285 int status, saved_errno;
1286 asl_msg_t *msg;
1287 char *str, *fmt, *estr;
1288 uint32_t i, len, elen, expand, my_msg;
1289 asl_client_t *asl;
1290
1291 asl = (asl_client_t *)ac;
1292 if (asl == NULL)
1293 {
1294 /*
1295 * Initialize _asl_global so that asl_new will have global data.
1296 * Not strictly necessary, but helps performance.
1297 */
1298 asl = _asl_open_default();
1299 if (asl == NULL) return -1;
1300 }
1301
1302 saved_errno = errno;
1303
1304 if (format == NULL) return -1;
1305
1306 msg = (asl_msg_t *)a;
1307
1308 my_msg = 0;
1309 if (msg == NULL)
1310 {
1311 my_msg = 1;
1312 msg = asl_new(ASL_TYPE_MSG);
1313 if (msg == NULL) return -1;
1314 }
1315
1316 if (msg->type != ASL_TYPE_MSG) return -1;
1317
1318 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
1319 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1320
1321 str = NULL;
1322 asprintf(&str, "%d", level);
1323 if (str == NULL)
1324 {
1325 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
1326 return -1;
1327 }
1328
1329 asl_set(msg, ASL_KEY_LEVEL, str);
1330 free(str);
1331
1332 /* insert strerror for %m */
1333 len = 0;
1334 elen = 0;
1335 estr = strdup(strerror(saved_errno));
1336 expand = 0;
1337
1338 if (estr != NULL)
1339 {
1340 elen = strlen(estr);
1341
1342 for (i = 0; format[i] != '\0'; i++)
1343 {
1344 if (format[i] == '%')
1345 {
1346 if (format[i+1] == '\0') len++;
1347 else if (format[i+1] == 'm')
1348 {
1349 expand = 1;
1350 len += elen;
1351 i++;
1352 }
1353 else
1354 {
1355 len += 2;
1356 i++;
1357 }
1358 }
1359 else len++;
1360 }
1361 }
1362
1363 fmt = (char *)format;
1364
1365 if (expand != 0)
1366 {
1367 fmt = malloc(len + 1);
1368 len = 0;
1369
1370 for (i = 0; format[i] != '\0'; i++)
1371 {
1372 if (format[i] == '%')
1373 {
1374 if (format[i+1] == '\0')
1375 {
1376 }
1377 else if (format[i+1] == 'm')
1378 {
1379 memcpy(fmt+len, estr, elen);
1380 len += elen;
1381 i++;
1382 }
1383 else
1384 {
1385 fmt[len++] = format[i++];
1386 fmt[len++] = format[i];
1387 }
1388 }
1389 else fmt[len++] = format[i];
1390 }
1391
1392 fmt[len] = '\0';
1393 }
1394
1395 if (estr != NULL) free(estr);
1396
1397 vasprintf(&str, fmt, ap);
1398 if (expand != 0) free(fmt);
1399
1400 if (str == NULL)
1401 {
1402 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
1403 return -1;
1404 }
1405
1406 asl_set(msg, ASL_KEY_MSG, str);
1407 free(str);
1408
1409 status = asl_send(ac, (aslmsg)msg);
1410
1411 if ((msg != NULL) && (my_msg != 0)) asl_free(msg);
1412 return status;
1413}
1414
1415/*
1416 * asl_log: log a message with a particular log level
1417 * msg: an aslmsg
1418 * level: the log level
1419 * format: A formating string followed by a list of arguments, like printf()
1420 * returns 0 for success, non-zero for failure
1421 */
1422int
1423asl_log(aslclient ac, aslmsg a, int level, const char *format, ...)
1424{
1425 va_list ap;
1426 int status;
1427
1428 if (format == NULL) return -1;
1429
1430 va_start(ap, format);
1431 status = asl_vlog(ac, a, level, format, ap);
1432 va_end(ap);
1433
1434 return status;
1435}
1436
1437#ifndef BUILDING_VARIANT
1438
1439/*
1440 * asl_send: send a message
1441 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1442 * has been used to set all of a message's attributes.
1443 * msg: an aslmsg
1444 * returns 0 for success, non-zero for failure
1445 */
1446int
1447asl_send(aslclient ac, aslmsg msg)
1448{
1449 char *str, *out;
1450 uint32_t i, len, level, lmask, outstatus, filter;
1451 const char *val;
1452 time_t tick;
1453 int status, rc_filter;
1454 asl_client_t *asl;
1455 int use_global_lock;
1456
1457 use_global_lock = 0;
1458 asl = (asl_client_t *)ac;
1459 if (asl == NULL)
1460 {
1461 asl = _asl_open_default();
1462 if (asl == NULL) return -1;
1463 use_global_lock = 1;
1464 }
1465
1466 if (msg == NULL) return 0;
1467
1468 level = ASL_LEVEL_DEBUG;
1469
1470 val = asl_get(msg, ASL_KEY_LEVEL);
1471 if (val != NULL) level = atoi(val);
1472
1473 lmask = ASL_FILTER_MASK(level);
1474
1475 filter = asl->filter;
1476 rc_filter = 0;
1477
1478 if (!(asl->options & ASL_OPT_NO_REMOTE))
1479 {
1480 pthread_mutex_lock(&_asl_global.lock);
1481
1482 if (_asl_global.notify_token >= 0)
1483 {
1484 status = notify_get_state(_asl_global.notify_token, &i);
1485 if ((status == NOTIFY_STATUS_OK) && (i != 0))
1486 {
1487 filter = i;
1488 rc_filter = 1;
1489 }
1490 }
1491
1492 if ((rc_filter == 0) && (_asl_global.master_token >= 0))
1493 {
1494 status = notify_get_state(_asl_global.master_token, &i);
1495 if ((status == NOTIFY_STATUS_OK) && (i != 0))
1496 {
1497 filter = i;
1498 }
1499 }
1500
1501 pthread_mutex_unlock(&_asl_global.lock);
1502 }
1503
1504 /*
1505 * Time, PID, UID, and GID values get set here
1506 */
1507 str = NULL;
1508 tick = time(NULL);
1509 asprintf(&str, "%u", tick);
1510 if (str != NULL)
1511 {
1512 asl_set(msg, ASL_KEY_TIME, str);
1513 free(str);
1514 }
1515
1516 str = NULL;
1517 asprintf(&str, "%u", getpid());
1518 if (str != NULL)
1519 {
1520 asl_set(msg, ASL_KEY_PID, str);
1521 free(str);
1522 }
1523
1524 str = NULL;
1525 asprintf(&str, "%d", getuid());
1526 if (str != NULL)
1527 {
1528 asl_set(msg, ASL_KEY_UID, str);
1529 free(str);
1530 }
1531
1532 str = NULL;
1533 asprintf(&str, "%u", getgid());
1534 if (str != NULL)
1535 {
1536 asl_set(msg, ASL_KEY_GID, str);
1537 free(str);
1538 }
1539
1540 len = 0;
1541 str = asl_msg_to_string((asl_msg_t *)msg, &len);
1542 if (str == NULL) return -1;
1543
1544 asprintf(&out, "%10u %s\n", len+1, str);
1545 free(str);
1546 if (out == NULL) return -1;
1547
1548 outstatus = 0;
1549
1550 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1551
1552 if ((filter != 0) && ((filter & lmask) != 0))
1553 {
1554 if (asl->sock == -1) _asl_connect(asl);
1555
1556 status = write(asl->sock, out, len + 12);
1557 if (status < 0)
1558 {
1559 /* Write failed - try resetting */
1560 asl->sock = -1;
1561 _asl_connect(asl);
1562 status = write(asl->sock, out, len + 12);
1563 if (status < 0) outstatus = -1;
1564 }
1565 }
1566
1567 if (asl->options & ASL_OPT_STDERR) fprintf(stderr, "%s", out);
1568
1569 for (i = 0; i < asl->fd_count; i++)
1570 {
1571 if (asl->fd_list[i] < 0) continue;
1572 status = write(asl->fd_list[i], out, len + 12);
1573 if (status < 0)
1574 {
1575 asl->fd_list[i] = -1;
1576 outstatus = -1;
1577 }
1578 }
1579
1580 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1581
1582 free(out);
1583
1584 return outstatus;
1585}
1586
1587char *
1588asl_msg_string(aslmsg a)
1589{
1590 uint32_t len;
1591
1592 return asl_msg_to_string((asl_msg_t *)a, &len);
1593}
1594
1595/*
1596 * asl_free: free a message
1597 * msg: an aslmsg to free
1598 */
1599void
1600asl_free(aslmsg a)
1601{
1602 uint32_t i;
1603 asl_msg_t *msg;
1604
1605 msg = (asl_msg_t *)a;
1606
1607 if (msg == NULL) return;
1608
1609 for (i = 0; i < msg->count; i++)
1610 {
1611 if (msg->key[i] != NULL) free(msg->key[i]);
1612 if (msg->val[i] != NULL) free(msg->val[i]);
1613 }
1614
1615 if (msg->count > 0)
1616 {
1617 if (msg->key != NULL) free(msg->key);
1618 if (msg->val != NULL) free(msg->val);
1619 if (msg->op != NULL) free(msg->op);
1620 }
1621
1622 free(msg);
1623}
1624
1625/*
1626 * asl_set_query: set arbitrary parameters of a query
1627 * Similar to als_set, but allows richer query operations.
1628 * See ASL_QUERY_OP_* above.
1629 * msg: an aslmsg
1630 * key: attribute key
1631 * value: attribute value
1632 * op: an operation from the set above.
1633 * returns 0 for success, non-zero for failure
1634 */
1635int asl_set_query(aslmsg a, const char *key, const char *val, uint32_t op)
1636{
1637 uint32_t i;
1638 char *dk, *dv;
1639 asl_msg_t *msg;
1640
1641 msg = (asl_msg_t *)a;
1642
1643 if (msg == NULL) return 0;
1644
1645 if (key == NULL) return -1;
1646
1647 dv = NULL;
1648
1649 if (streq(key, ASL_KEY_LEVEL))
1650 {
1651 if (val == NULL) return -1;
1652 if (val[0] == '\0') return -1;
1653 if ((val[0] >= '0') && (val[0] <= '9'))
1654 {
1655 i = atoi(val);
1656 asprintf(&dv, "%d", i);
1657 if (dv == NULL) return -1;
1658 }
1659 else if (!strcasecmp(val, ASL_STRING_EMERG)) dv = strdup("0");
1660 else if (!strcasecmp(val, ASL_STRING_ALERT)) dv = strdup("1");
1661 else if (!strcasecmp(val, ASL_STRING_CRIT)) dv = strdup("2");
1662 else if (!strcasecmp(val, ASL_STRING_ERR)) dv = strdup("3");
1663 else if (!strcasecmp(val, ASL_STRING_WARNING)) dv = strdup("4");
1664 else if (!strcasecmp(val, ASL_STRING_NOTICE)) dv = strdup("5");
1665 else if (!strcasecmp(val, ASL_STRING_INFO)) dv = strdup("6");
1666 else if (!strcasecmp(val, ASL_STRING_DEBUG)) dv = strdup("7");
1667 else return -1;
1668 }
1669
1670 if ((dv == NULL) && (val != NULL))
1671 {
1672 dv = strdup(val);
1673 if (dv == NULL) return -1;
1674 }
1675
1676 for (i = 0; i < msg->count; i++)
1677 {
1678 if (msg->key[i] == NULL) continue;
1679
1680 if ((msg->type != ASL_TYPE_QUERY) && (streq(msg->key[i], key)))
1681 {
1682 if (msg->val[i] != NULL) free(msg->val[i]);
1683 msg->val[i] = NULL;
1684 if (val != NULL) msg->val[i] = dv;
1685 if (msg->op != NULL) msg->op[i] = op;
1686 return 0;
1687 }
1688 }
1689
1690 if (msg->count == 0)
1691 {
1692 msg->key = (char **)calloc(1, sizeof(char *));
1693 if (msg->key == NULL)
1694 {
1695 asl_free(msg);
1696 return -1;
1697 }
1698
1699 msg->val = (char **)calloc(1, sizeof(char *));
1700 if (msg->val == NULL)
1701 {
1702 asl_free(msg);
1703 return -1;
1704 }
1705
1706 if (msg->type == ASL_TYPE_QUERY)
1707 {
1708 msg->op = (uint32_t *)calloc(1, sizeof(uint32_t));
1709 if (msg->op == NULL)
1710 {
1711 asl_free(msg);
1712 return -1;
1713 }
1714 }
1715 }
1716 else
1717 {
1718 msg->key = (char **)realloc(msg->key, (msg->count + 1) * sizeof(char *));
1719 if (msg->key == NULL)
1720 {
1721 asl_free(msg);
1722 return -1;
1723 }
1724
1725 msg->val = (char **)realloc(msg->val, (msg->count + 1) * sizeof(char *));
1726 if (msg->val == NULL)
1727 {
1728 asl_free(msg);
1729 return -1;
1730 }
1731
1732 if (msg->type == ASL_TYPE_QUERY)
1733 {
1734 msg->op = (uint32_t *)realloc(msg->op, (msg->count + 1) * sizeof(uint32_t));
1735 if (msg->op == NULL)
1736 {
1737 asl_free(msg);
1738 return -1;
1739 }
1740 }
1741 }
1742
1743 dk = strdup(key);
1744 if (dk == NULL) return -1;
1745
1746 msg->key[msg->count] = dk;
1747 msg->val[msg->count] = dv;
1748 if (msg->op != NULL) msg->op[msg->count] = op;
1749 msg->count++;
1750
1751 return 0;
1752}
1753
1754/*
1755 * asl_set: set attributes of a message
1756 * msg: an aslmsg
1757 * key: attribute key
1758 * value: attribute value
1759 * returns 0 for success, non-zero for failure
1760 */
1761int
1762asl_set(aslmsg msg, const char *key, const char *val)
1763{
1764 return asl_set_query(msg, key, val, 0);
1765}
1766
1767/*
1768 * asl_unset: remove attributes of a message
1769 * msg: an aslmsg
1770 * key: attribute key
1771 * returns 0 for success, non-zero for failure
1772 */
1773int
1774asl_unset(aslmsg a, const char *key)
1775{
1776 uint32_t i, j;
1777 asl_msg_t *msg;
1778
1779 msg = (asl_msg_t *)a;
1780
1781 if (msg == NULL) return 0;
1782 if (key == NULL) return 0;
1783
1784 for (i = 0; i < msg->count; i++)
1785 {
1786 if (msg->key[i] == NULL) continue;
1787
1788 if (streq(msg->key[i], key))
1789 {
1790 free(msg->key[i]);
1791 if (msg->val[i] != NULL) free(msg->val[i]);
1792
1793 for (j = i + 1; j < msg->count; j++, i++)
1794 {
1795 msg->key[i] = msg->key[j];
1796 msg->val[i] = msg->val[j];
1797 if (msg->op != NULL) msg->op[i] = msg->op[j];
1798 }
1799
1800 msg->count--;
1801
1802 if (msg->count == 0)
1803 {
1804 free(msg->key);
1805 msg->key = NULL;
1806
1807 free(msg->val);
1808 msg->val = NULL;
1809
1810 if (msg->op != NULL) free(msg->op);
1811 msg->op = NULL;
1812 }
1813 else
1814 {
1815 msg->key = (char **)realloc(msg->key, msg->count * sizeof(char *));
1816 if (msg->key == NULL) return -1;
1817
1818 msg->val = (char **)realloc(msg->val, msg->count * sizeof(char *));
1819 if (msg->val == NULL) return -1;
1820
1821 if (msg->op != NULL)
1822 {
1823 msg->op = (uint32_t *)realloc(msg->op, msg->count * sizeof(uint32_t));
1824 if (msg->op == NULL) return -1;
1825 }
1826 }
1827
1828 return 0;
1829 }
1830 }
1831
1832 return 0;
1833}
1834
1835/*
1836 * asl_search: Search for messages matching the criteria described
1837 * by the aslmsg . The caller should set the attributes to match using
1838 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
1839 * used for attributes set with asl_set().
1840 * a: an aslmsg
1841 * returns: a set of messages that can be iterated over using aslresp_next(),
1842 * and the values can be retrieved using aslresp_get.
1843 */
1844aslresponse
1845asl_search(aslclient ac, aslmsg a)
1846{
1847 FILE *log;
1848 asl_msg_t *q, *m;
1849 asl_search_result_t *res;
1850 char *str;
1851
1852 q = (asl_msg_t *)a;
1853
1854 if (q == NULL) return 0;
1855
1856 log = fopen(_PATH_ASL_OUT, "r");
1857 if (log == NULL) return NULL;
1858
1859 res = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
1860
1861 while (NULL != (str = _get_line_from_file(log)))
1862 {
1863 m = asl_msg_from_string(str);
1864 if (m == NULL) continue;
1865 if (asl_msg_cmp(q, m) == 0)
1866 {
1867 asl_free(m);
1868 continue;
1869 }
1870
1871 if (res->count == 0)
1872 {
1873 res->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1874 }
1875 else
1876 {
1877 res->msg = (asl_msg_t **)realloc(res->msg, (res->count + 1) * sizeof(asl_msg_t *));
1878 }
1879
1880 res->msg[res->count] = m;
1881 res->count++;
1882 }
1883
1884 fclose(log);
1885 return res;
1886}
1887
1888/*
1889 * aslresponse_next: Iterate over responses returned from asl_search()
1890 * a: a response returned from asl_search();
1891 * returns: The next log message (an aslmsg) or NULL on failure
1892 */
1893aslmsg
1894aslresponse_next(aslresponse r)
1895{
1896 asl_search_result_t *res;
1897 aslmsg m;
1898
1899 res = (asl_search_result_t *)r;
1900 if (res == NULL) return NULL;
1901
1902 if (res->curr >= res->count) return NULL;
1903 m = res->msg[res->curr];
1904 res->curr++;
1905
1906 return m;
1907}
1908
1909/*
1910 * aslresponse_free: Free a response returned from asl_search()
1911 * a: a response returned from asl_search()
1912 */
1913void
1914aslresponse_free(aslresponse r)
1915{
1916 asl_search_result_t *res;
1917 uint32_t i;
1918
1919 res = (asl_search_result_t *)r;
1920 if (res == NULL) return;
1921
1922 for (i = 0; i < res->count; i++) free(res->msg[i]);
1923 free(res->msg);
1924 free(res);
1925}
1926
1927int
1928asl_syslog_faciliy_name_to_num(const char *name)
1929{
1930 if (name == NULL) return -1;
1931
1932 if (strcaseeq(name, "auth")) return LOG_AUTH;
1933 if (strcaseeq(name, "authpriv")) return LOG_AUTHPRIV;
1934 if (strcaseeq(name, "cron")) return LOG_CRON;
1935 if (strcaseeq(name, "daemon")) return LOG_DAEMON;
1936 if (strcaseeq(name, "ftp")) return LOG_FTP;
1937 if (strcaseeq(name, "install")) return LOG_INSTALL;
1938 if (strcaseeq(name, "kern")) return LOG_KERN;
1939 if (strcaseeq(name, "lpr")) return LOG_LPR;
1940 if (strcaseeq(name, "mail")) return LOG_MAIL;
1941 if (strcaseeq(name, "netinfo")) return LOG_NETINFO;
1942 if (strcaseeq(name, "remoteauth")) return LOG_REMOTEAUTH;
1943 if (strcaseeq(name, "news")) return LOG_NEWS;
1944 if (strcaseeq(name, "security")) return LOG_AUTH;
1945 if (strcaseeq(name, "syslog")) return LOG_SYSLOG;
1946 if (strcaseeq(name, "user")) return LOG_USER;
1947 if (strcaseeq(name, "uucp")) return LOG_UUCP;
1948 if (strcaseeq(name, "local0")) return LOG_LOCAL0;
1949 if (strcaseeq(name, "local1")) return LOG_LOCAL1;
1950 if (strcaseeq(name, "local2")) return LOG_LOCAL2;
1951 if (strcaseeq(name, "local3")) return LOG_LOCAL3;
1952 if (strcaseeq(name, "local4")) return LOG_LOCAL4;
1953 if (strcaseeq(name, "local5")) return LOG_LOCAL5;
1954 if (strcaseeq(name, "local6")) return LOG_LOCAL6;
1955 if (strcaseeq(name, "local7")) return LOG_LOCAL7;
1956 if (strcaseeq(name, "launchd")) return LOG_LAUNCHD;
1957
1958 return -1;
1959}
1960
1961const char *
1962asl_syslog_faciliy_num_to_name(int n)
1963{
1964 if (n < 0) return NULL;
1965
1966 if (n == LOG_AUTH) return "auth";
1967 if (n == LOG_AUTHPRIV) return "authpriv";
1968 if (n == LOG_CRON) return "cron";
1969 if (n == LOG_DAEMON) return "daemon";
1970 if (n == LOG_FTP) return "ftp";
1971 if (n == LOG_INSTALL) return "install";
1972 if (n == LOG_KERN) return "kern";
1973 if (n == LOG_LPR) return "lpr";
1974 if (n == LOG_MAIL) return "mail";
1975 if (n == LOG_NETINFO) return "netinfo";
1976 if (n == LOG_REMOTEAUTH) return "remoteauth";
1977 if (n == LOG_NEWS) return "news";
1978 if (n == LOG_AUTH) return "security";
1979 if (n == LOG_SYSLOG) return "syslog";
1980 if (n == LOG_USER) return "user";
1981 if (n == LOG_UUCP) return "uucp";
1982 if (n == LOG_LOCAL0) return "local0";
1983 if (n == LOG_LOCAL1) return "local1";
1984 if (n == LOG_LOCAL2) return "local2";
1985 if (n == LOG_LOCAL3) return "local3";
1986 if (n == LOG_LOCAL4) return "local4";
1987 if (n == LOG_LOCAL5) return "local5";
1988 if (n == LOG_LOCAL6) return "local6";
1989 if (n == LOG_LOCAL7) return "local7";
1990 if (n == LOG_LAUNCHD) return "launchd";
1991
1992 return NULL;
1993}
1994
1995/*
1996 * utility for converting a time string into a time_t
1997 * we only deal with the following formats:
1998 * Canonical form YYYY.MM.DD hh:mm:ss UTC
1999 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
2000 * absolute form - # seconds since the epoch (e.g. 1095789191)
2001 * relative time - seconds before or after now (e.g. -300, +43200)
2002 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
2003 */
2004
2005#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$"
2006#define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
2007#define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
2008#define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
2009
2010#define SECONDS_PER_MINUTE 60
2011#define SECONDS_PER_HOUR 3600
2012#define SECONDS_PER_DAY 86400
2013#define SECONDS_PER_WEEK 604800
2014
2015/*
2016 * We use the last letter in the month name to determine
2017 * the month number (0-11). There are two collisions:
2018 * Jan and Jun both end in n
2019 * Mar and Apr both end in r
2020 * In these cases we check the second letter.
2021 *
2022 * The MTH_LAST array maps the last letter to a number.
2023 */
2024static 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};
2025
2026static int
2027_month_num(char *s)
2028{
2029 int i;
2030 int8_t v8;
2031
2032 v8 = -1;
2033 if (s[2] > 90) v8 = s[2] - 'a';
2034 else v8 = s[2] - 'A';
2035
2036 if ((v8 < 0) || (v8 > 25)) return -1;
2037
2038 v8 = MTH_LAST[v8];
2039 if (v8 < 0) return -1;
2040
2041 i = v8;
2042 if ((i == 5) && ((s[1] == 'a') || (s[1] == 'A'))) return 0;
2043 if ((i == 3) && ((s[1] == 'a') || (s[1] == 'A'))) return 2;
2044 return i;
2045}
2046
2047time_t
2048asl_parse_time(const char *in)
2049{
2050 int len, y, status, rflags, factor;
2051 struct tm t;
2052 time_t tick, delta;
2053 char *str, *p, *x;
2054 static regex_t rex_canon, rex_ctime, rex_abs, rex_rel;
2055 static int init_canon = 0;
2056 static int init_ctime = 0;
2057 static int init_abs = 0;
2058 static int init_rel = 0;
2059
2060 if (in == NULL) return -1;
2061
2062 rflags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
2063
2064 if (init_canon == 0)
2065 {
2066 memset(&rex_canon, 0, sizeof(regex_t));
2067 status = regcomp(&rex_canon, CANONICAL_TIME_REX, rflags);
2068 if (status != 0) return -1;
2069 init_canon = 1;
2070 }
2071
2072 if (init_ctime == 0)
2073 {
2074 memset(&rex_ctime, 0, sizeof(regex_t));
2075 status = regcomp(&rex_ctime, CTIME_REX, rflags);
2076 if (status != 0) return -1;
2077 init_ctime = 1;
2078 }
2079
2080 if (init_abs == 0)
2081 {
2082 memset(&rex_abs, 0, sizeof(regex_t));
2083 status = regcomp(&rex_abs, ABSOLUTE_TIME_REX, rflags);
2084 if (status != 0) return -1;
2085 init_abs = 1;
2086 }
2087
2088 if (init_rel == 0)
2089 {
2090 memset(&rex_rel, 0, sizeof(regex_t));
2091 status = regcomp(&rex_rel, RELATIVE_TIME_REX, rflags);
2092 if (status != 0) return -1;
2093 init_rel = 1;
2094 }
2095
2096 len = strlen(in) + 1;
2097
2098 if (regexec(&rex_abs, in, 0, NULL, 0) == 0)
2099 {
2100 /*
2101 * Absolute time (number of seconds since the epoch)
2102 */
2103 str = strdup(in);
2104 if ((str[len-2] == 's') || (str[len-2] == 'S')) str[len-2] = '\0';
2105
2106 tick = atoi(str);
2107 free(str);
2108
2109 return tick;
2110 }
2111 else if (regexec(&rex_rel, in, 0, NULL, 0) == 0)
2112 {
2113 /*
2114 * Reletive time (number of seconds before or after right now)
2115 */
2116 str = strdup(in);
2117
2118 factor = 1;
2119
2120 if ((str[len-2] == 's') || (str[len-2] == 'S'))
2121 {
2122 str[len-2] = '\0';
2123 }
2124 else if ((str[len-2] == 'm') || (str[len-2] == 'M'))
2125 {
2126 str[len-2] = '\0';
2127 factor = SECONDS_PER_MINUTE;
2128 }
2129 else if ((str[len-2] == 'h') || (str[len-2] == 'H'))
2130 {
2131 str[len-2] = '\0';
2132 factor = SECONDS_PER_HOUR;
2133 }
2134 else if ((str[len-2] == 'd') || (str[len-2] == 'D'))
2135 {
2136 str[len-2] = '\0';
2137 factor = SECONDS_PER_DAY;
2138 }
2139 else if ((str[len-2] == 'w') || (str[len-2] == 'W'))
2140 {
2141 str[len-2] = '\0';
2142 factor = SECONDS_PER_WEEK;
2143 }
2144
2145 tick = time(NULL);
2146 delta = factor * atoi(str);
2147 tick += delta;
2148
2149 free(str);
2150
2151 return tick;
2152 }
2153 else if (regexec(&rex_canon, in, 0, NULL, 0) == 0)
2154 {
2155 memset(&t, 0, sizeof(struct tm));
2156 str = strdup(in);
2157
2158 /* Get year */
2159 x = str;
2160 p = strchr(x, '.');
2161 *p = '\0';
2162 t.tm_year = atoi(x) - 1900;
2163
2164 /* Get month */
2165 x = p + 1;
2166 p = strchr(x, '.');
2167 *p = '\0';
2168 t.tm_mon = atoi(x) - 1;
2169
2170 /* Get day */
2171 x = p + 1;
2172 p = strchr(x, ' ');
2173 *p = '\0';
2174 t.tm_mday = atoi(x);
2175
2176 /* Get hour */
2177 for (x = p + 1; *x == ' '; x++);
2178 p = strchr(x, ':');
2179 *p = '\0';
2180 t.tm_hour = atoi(x);
2181
2182 /* Get minutes */
2183 x = p + 1;
2184 p = strchr(x, ':');
2185 *p = '\0';
2186 t.tm_min = atoi(x);
2187
2188 /* Get seconds */
2189 x = p + 1;
2190 p = strchr(x, ' ');
2191 *p = '\0';
2192 t.tm_sec = atoi(x);
2193
2194 free(str);
2195 return timegm(&t);
2196 }
2197 else if (regexec(&rex_ctime, in, 0, NULL, 0) == 0)
2198 {
2199 /* We assume it's in the current year */
2200 memset(&t, 0, sizeof(struct tm));
2201 tick = time(NULL);
2202 gmtime_r(&tick, &t);
2203 y = t.tm_year;
2204
2205 memset(&t, 0, sizeof(struct tm));
2206 str = strdup(in);
2207
2208 t.tm_year = y;
2209 t.tm_mon = _month_num(str);
2210 if (t.tm_mon < 0) return -1;
2211
2212 for (x = strchr(str, ' '); *x == ' '; x++);
2213 p = strchr(x, ' ');
2214 *p = '\0';
2215 t.tm_mday = atoi(x);
2216
2217 /* Get hour */
2218 for (x = p + 1; *x == ' '; x++);
2219 p = strchr(x, ':');
2220 *p = '\0';
2221 t.tm_hour = atoi(x);
2222
2223 /* Get minutes */
2224 x = p + 1;
2225 p = strchr(x, ':');
2226 *p = '\0';
2227 t.tm_min = atoi(x);
2228
2229 /* Get seconds */
2230 x = p + 1;
2231 t.tm_sec = atoi(x);
2232
2233 t.tm_isdst = -1;
2234
2235 free(str);
2236 return mktime(&t);
2237 }
2238
2239 return -1;
2240}
2241
2242#ifdef ASL_SYSLOG_COMPAT
2243
2244__private_extern__ void
2245asl_syslog_syslog(int pri, const char *fmt, ...)
2246{
2247 va_list ap;
2248 asl_msg_t *m;
2249
2250 if (fmt == NULL) return;
2251
2252 m = asl_new(ASL_TYPE_MSG);
2253
2254 va_start(ap, fmt);
2255 asl_vlog(NULL, m, pri, fmt, ap);
2256 va_end(ap);
2257
2258 asl_free(m);
2259}
2260
2261__private_extern__ void
2262asl_syslog_vsyslog(int pri, const char *fmt, va_list ap)
2263{
2264 asl_msg_t *m;
2265
2266 m = asl_new(ASL_TYPE_MSG);
2267 asl_vlog(NULL, m, pri, fmt, ap);
2268 asl_free(m);
2269}
2270
2271__private_extern__ void
2272asl_syslog_openlog(const char *ident, int flags, int facility)
2273{
2274 const char *fname;
2275 uint32_t opts;
2276
2277 opts = 0;
2278
2279 if (flags & LOG_NDELAY) opts |= ASL_OPT_NO_DELAY;
2280 if (flags & LOG_PERROR) opts |= ASL_OPT_STDERR;
2281
2282 fname = asl_syslog_faciliy_num_to_name(facility);
2283 if (fname == NULL) fname = "user";
2284
2285 asl_global_client = asl_open(ident, fname, opts);
2286}
2287
2288__private_extern__ void
2289asl_syslog_closelog()
2290{
2291 asl_close();
2292}
2293
2294__private_extern__ int
2295asl_syslog_setlogmask(int p)
2296{
2297 return asl_set_filter(p);
2298}
2299
2300#endif ASL_SYSLOG_COMPAT
2301
2302#endif /* BUILDING_VARIANT */