2 * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
36 #include <crt_externs.h>
38 #include <asl_private.h>
39 #include <asl_store.h>
42 #include <mach/mach.h>
43 #include <mach/std_types.h>
45 #include <mach/mach_types.h>
46 #include <sys/types.h>
47 #include <servers/bootstrap.h>
51 #define streq(A, B) (strcmp(A, B) == 0)
52 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
54 #ifndef ASL_QUERY_OP_FALSE
55 #define ASL_QUERY_OP_FALSE 0
58 #define forever for(;;)
78 #define XML_TAG_STRING 1
79 #define XML_TAG_DATA 2
81 #define FETCH_BATCH 256
84 time_t asl_parse_time(const char *);
85 const char *asl_syslog_faciliy_num_to_name(int n
);
86 __private_extern__ asl_client_t
*_asl_open_default();
87 __private_extern__
int _asl_send_level_message(aslclient ac
, aslmsg msg
, int level
, const char *message
);
90 uint32_t notify_register_plain(const char *name
, int *out_token
);
93 int asl_is_utf8(const char *str
);
94 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
96 /* fork handling in syslog.c */
97 extern void _syslog_fork_child();
99 /* character encoding lengths */
100 static const uint8_t char_encode_len
[128] =
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
108 static const char *cvis_7_13
= "abtnvfr";
116 uint64_t proc_filter
;
117 uint64_t master_filter
;
119 mach_port_t server_port
;
121 pthread_mutex_t lock
;
122 pthread_mutex_t port_lock
;
126 #ifndef BUILDING_VARIANT
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
};
129 #define ASL_SERVICE_NAME "com.apple.system.logger"
132 * Called from the child process inside fork() to clean up
133 * inherited state from the parent process.
135 * NB. A lock isn't required, since we're single threaded in this call.
137 __private_extern__
void
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;
145 _asl_global
.port_count
= 0;
146 _asl_global
.server_port
= MACH_PORT_NULL
;
148 /* clean up in syslog.c */
149 _syslog_fork_child();
153 _asl_notify_open(int do_lock
)
159 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
161 _asl_global
.notify_count
++;
163 if (_asl_global
.notify_token
!= -1)
165 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
169 if (_asl_global
.rc_change_token
== -1)
171 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
172 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
175 if (_asl_global
.master_token
== -1)
177 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
178 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
183 if (euid
== 0) asprintf(¬ify_name
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, getpid());
184 else asprintf(¬ify_name
, "user.uid.%d.syslog.%d", euid
, getpid());
186 if (notify_name
!= NULL
)
188 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
190 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
193 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
195 if (_asl_global
.notify_token
== -1) return -1;
202 pthread_mutex_lock(&_asl_global
.lock
);
204 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
206 if (_asl_global
.notify_count
> 0)
208 pthread_mutex_unlock(&_asl_global
.lock
);
212 if (_asl_global
.rc_change_token
> 0) notify_cancel(_asl_global
.rc_change_token
);
213 _asl_global
.rc_change_token
= -1;
215 if (_asl_global
.master_token
> 0) notify_cancel(_asl_global
.master_token
);
216 _asl_global
.master_token
= -1;
218 if (_asl_global
.notify_token
> 0) notify_cancel(_asl_global
.notify_token
);
219 _asl_global
.notify_token
= -1;
221 pthread_mutex_unlock(&_asl_global
.lock
);
225 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
229 kern_return_t kstatus
;
231 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
242 pthread_mutex_lock(&(_asl_global
.port_lock
));
244 if (_asl_global
.server_port
== MACH_PORT_NULL
)
246 _asl_global
.port_count
= 0;
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
;
254 _asl_global
.port_count
++;
257 pthread_mutex_unlock(&(_asl_global
.port_lock
));
263 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
267 asl
->name
= strdup(ident
);
268 if (asl
->name
== NULL
)
270 if (asl
->sock
>= 0) close(asl
->sock
);
277 name
= *(*_NSGetArgv());
280 x
= strrchr(name
, '/');
283 asl
->name
= strdup(x
);
284 if (asl
->name
== NULL
)
286 if (asl
->sock
>= 0) close(asl
->sock
);
293 asl
->facility
= NULL
;
294 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
295 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
296 if (asl
->facility
== NULL
)
298 if (asl
->sock
>= 0) close(asl
->sock
);
303 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
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
);
307 return (aslclient
)asl
;
311 asl_close(aslclient ac
)
316 asl
= (asl_client_t
*)ac
;
317 if (asl
== NULL
) return;
319 if (asl
->sock
>= 0) close(asl
->sock
);
321 pthread_mutex_lock(&(_asl_global
.port_lock
));
323 if (_asl_global
.port_count
> 0) _asl_global
.port_count
--;
324 if (_asl_global
.port_count
== 0)
326 mach_port_deallocate(mach_task_self(), _asl_global
.server_port
);
327 _asl_global
.server_port
= MACH_PORT_NULL
;
330 pthread_mutex_unlock(&(_asl_global
.port_lock
));
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
);
337 if (asl
->fd_mfmt
!= NULL
)
339 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
343 if (asl
->fd_tfmt
!= NULL
)
345 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
349 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
351 memset(asl
, 0, sizeof(asl_client_t
));
355 __private_extern__ asl_client_t
*
358 if (_asl_global
.asl
!= NULL
) return _asl_global
.asl
;
360 pthread_mutex_lock(&_asl_global
.lock
);
361 if (_asl_global
.asl
!= NULL
)
363 pthread_mutex_unlock(&_asl_global
.lock
);
364 return _asl_global
.asl
;
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.
372 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
374 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
375 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
377 /* Now call _asl_notify_open(0) to finish the work */
380 pthread_mutex_unlock(&_asl_global
.lock
);
382 return _asl_global
.asl
;
386 _asl_msg_index(asl_msg_t
*msg
, const char *k
)
390 if (msg
== NULL
) return (uint32_t)-1;
391 if (k
== NULL
) return (uint32_t)-1;
393 for (i
= 0; i
< msg
->count
; i
++)
395 if (msg
->key
[i
] == NULL
) continue;
396 if (streq(msg
->key
[i
], k
)) return i
;
403 _asl_encode_char(char **m
, uint32_t *x
, uint32_t c
, uint32_t encode
, uint32_t encode_space
)
412 /* NUL is not allowed */
415 /* Meta chars get \M prefix */
418 /* except meta-space, which is \240 */
438 /* space is either ' ' or \s */
441 if (encode_space
== 0)
457 if ((meta
== 0) && (c
== 92))
466 /* [ and ] are escaped in ASL encoding */
467 if ((encode
== ASL_ENCODE_ASL
) && (meta
== 0) && ((c
== 91) || (c
== 93)))
492 /* 33-126 are printable (add a '-' prefix for meta) */
493 if ((c
>= 33) && (c
<= 126))
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))
511 *p
++ = cvis_7_13
[c
- 7];
517 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
518 if ((c
>= 0) && (c
<= 31))
537 _asl_append_string(char **m
, uint32_t *x
, const char *s
, uint32_t encode
, uint32_t escspace
)
539 uint32_t i
, n
, spextra
;
543 if (m
== NULL
) return;
544 if (x
== NULL
) return;
545 if (s
== NULL
) return;
547 if (encode
== ASL_ENCODE_NONE
)
549 /* no encoding - just allocate enough space and copy the string */
561 *m
= reallocf(*m
, n
+ (*x
));
564 if (*m
== NULL
) return;
566 memcpy((*m
) + (*x
) - 1, s
, n
+ 1);
571 else if (encode
== ASL_ENCODE_SAFE
)
574 * Minor encoding to reduce the likelyhood of spoof attacks.
576 * - append a tab after newlines
577 * - translate \r to newline & append a tab
578 * - map backspace to ^H
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.
584 for (i
= 0; s
[i
] != '\0'; i
++)
588 if ((c
== 10) || (c
== 13) || (c
== 8)) n
++;
600 *m
= reallocf(*m
, n
+ (*x
));
603 if (*m
== NULL
) return;
607 for (i
= 0; s
[i
] != '\0'; i
++)
610 if ((c
== 10) || (c
== 13))
634 if (escspace
!= 0) spextra
= 1;
637 for (i
= 0; s
[i
] != '\0'; i
++)
645 else if ((c
== 91) || (c
== 93))
647 if (encode
== ASL_ENCODE_ASL
) n
+= 2;
652 n
+= char_encode_len
[c
];
653 if (c
== 32) n
+= spextra
;
666 *m
= reallocf(*m
, n
+ (*x
));
669 if (*m
== NULL
) return;
671 for (i
= 0; s
[i
] != '\0'; i
++)
674 _asl_encode_char(m
, x
, c
, encode
, escspace
);
681 _asl_append_xml_string(char **m
, uint32_t *x
, char *s
)
687 if (m
== NULL
) return;
688 if (x
== NULL
) return;
689 if (s
== NULL
) return;
692 for (i
= 0; s
[i
] != '\0'; i
++)
697 * XML wants & < > " and '
698 * We use &#xnn; for control chars.
699 * Everything else just gets printed "as is" (we know the input is UTF8)
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;
719 *m
= reallocf(*m
, n
+ (*x
));
722 if (*m
== NULL
) return;
724 for (i
= 0; s
[i
] != '\0'; i
++)
731 memcpy(p
, "&", 5);
739 memcpy(p
, "<", 4);
747 memcpy(p
, ">", 4);
755 memcpy(p
, """, 6);
763 memcpy(p
, "'", 6);
770 snprintf(tmp
, sizeof(tmp
), "&#x%02hhu;", c
);
790 _asl_append_xml_tag(char **m
, uint32_t *x
, int tag
, char *s
)
794 if (m
== NULL
) return;
795 if (x
== NULL
) return;
797 if (tag
== XML_TAG_KEY
)
799 _asl_append_string(m
, x
, "\t\t<key>", ASL_ENCODE_NONE
, 0);
800 _asl_append_xml_string(m
, x
, s
);
801 _asl_append_string(m
, x
, "</key>\n", ASL_ENCODE_NONE
, 0);
805 if (tag
== XML_TAG_STRING
)
807 _asl_append_string(m
, x
, "\t\t<string>", ASL_ENCODE_NONE
, 0);
808 _asl_append_xml_string(m
, x
, s
);
809 _asl_append_string(m
, x
, "</string>\n", ASL_ENCODE_NONE
, 0);
813 if (tag
== XML_TAG_DATA
)
815 _asl_append_string(m
, x
, "\t\t<data>", ASL_ENCODE_NONE
, 0);
816 b64
= (char *)asl_b64_encode((uint8_t *)s
, strlen(s
));
819 _asl_append_string(m
, x
, b64
, ASL_ENCODE_NONE
, 0);
822 _asl_append_string(m
, x
, "</data>\n", ASL_ENCODE_NONE
, 0);
828 _asl_append_op(char **m
, uint32_t *x
, uint32_t op
)
833 if (m
== NULL
) return;
834 if (x
== NULL
) return;
836 if (op
== ASL_QUERY_OP_NULL
) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
839 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
841 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
843 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
845 if (op
& ASL_QUERY_OP_PREFIX
)
847 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
848 else opstr
[i
++] = 'A';
850 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
852 switch (op
& ASL_QUERY_OP_TRUE
)
854 case ASL_QUERY_OP_EQUAL
:
857 case ASL_QUERY_OP_GREATER
:
860 case ASL_QUERY_OP_GREATER_EQUAL
:
864 case ASL_QUERY_OP_LESS
:
867 case ASL_QUERY_OP_LESS_EQUAL
:
871 case ASL_QUERY_OP_NOT_EQUAL
:
874 case ASL_QUERY_OP_TRUE
:
881 if (i
== 0) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
884 return _asl_append_string(m
, x
, opstr
, ASL_ENCODE_NONE
, 0);
888 _asl_time_string(int fmt
, const char *str
)
898 if (str
!= NULL
) tick
= asl_parse_time(str
);
902 asprintf(&out
, "%lu", 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
);
915 ltime
= ctime_r(&tick
, ltbuf
);
916 if (ltime
== NULL
) return NULL
;
918 asprintf(&out
, "%s", ltime
);
926 _asl_msg_to_string_time_fmt(asl_msg_t
*msg
, uint32_t *len
, int tf
)
933 if (msg
== NULL
) return NULL
;
941 if (out
== NULL
) return NULL
;
946 for (i
= 0; i
< msg
->count
; i
++)
948 if (msg
->key
[i
] == NULL
) continue;
949 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
950 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
952 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
954 if ((tf
!= TFMT_SEC
) && (!strcmp(msg
->key
[i
], ASL_KEY_TIME
)))
956 s
= _asl_time_string(tf
, msg
->val
[i
]);
959 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
960 _asl_append_string(&out
, &outlen
, s
, ASL_ENCODE_ASL
, 0);
963 else if (msg
->val
[i
] != NULL
)
965 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
966 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
969 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
972 _asl_append_string(&out
, &outlen
, "\n", ASL_ENCODE_NONE
, 0);
979 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
986 if (msg
== NULL
) return NULL
;
992 if (msg
->type
== ASL_TYPE_QUERY
)
994 _asl_append_string(&out
, &outlen
, "Q ", ASL_ENCODE_NONE
, 0);
995 if (out
== NULL
) return NULL
;
1000 if (out
== NULL
) return NULL
;
1005 for (i
= 0; i
< msg
->count
; i
++)
1007 if (msg
->key
[i
] == NULL
) continue;
1009 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
1010 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
1012 if (msg
->type
== ASL_TYPE_QUERY
)
1014 _asl_append_op(&out
, &outlen
, msg
->op
[i
]);
1015 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
1018 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
1020 if (msg
->val
[i
] != NULL
)
1022 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
1023 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
1026 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
1034 _asl_msg_op_from_string(char *o
)
1038 op
= ASL_QUERY_OP_NULL
;
1040 if (o
== NULL
) return op
;
1042 for (i
= 0; o
[i
] != '\0'; i
++)
1044 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
1045 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
1046 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
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
;
1062 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
1064 char *str
, *out
, c
, oval
;
1065 uint32_t i
, len
, n
, outlen
;
1069 if (p
== NULL
) return NULL
;
1070 if (*p
== NULL
) return NULL
;
1071 if (**p
== '\0') return NULL
;
1073 /* skip one space if it's there (word separator) */
1074 if (**p
== ' ') (*p
)++;
1076 /* skip leading white space */
1079 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
1082 if (**p
== '\0') return NULL
;
1083 if (**p
== '\n') return NULL
;
1094 if (out
== NULL
) return NULL
;
1101 /* scan for token and calulate it's length (input and decoded output len) */
1109 /* stop scanning when we hit a delimiter */
1110 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
1116 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
1121 if (str
[++len
] == '\0') return NULL
;
1125 if (str
[++len
] == '\0') return NULL
;
1126 if (str
[++len
] == '\0') return NULL
;
1128 else if ((c
>= '0') && (c
<= '3'))
1130 if (str
[++len
] == '\0') return NULL
;
1131 if (str
[++len
] == '\0') return NULL
;
1145 if ((len
== 0) && (**p
== ']'))
1150 if (out
== NULL
) return NULL
;
1159 out
= malloc(outlen
+ 1);
1160 if (out
== NULL
) return NULL
;
1163 for (i
= 0; i
< len
; i
++)
1220 if (str
[i
] == '?') out
[n
++] = 127;
1221 else out
[n
++] = str
[i
] - 64;
1230 if (str
[i
] == '?') out
[n
++] = 255;
1231 else out
[n
++] = str
[i
] + 64;
1236 out
[n
++] = str
[i
] + 128;
1246 else if ((c
>= '0') && (c
<= '3'))
1248 oval
= (c
- '0') * 64;
1252 if ((c
< '0') || (c
> '7'))
1259 oval
+= ((c
- '0') * 8);
1263 if ((c
< '0') || (c
> '7'))
1284 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
1295 asl_msg_from_string(const char *buf
)
1297 uint32_t tt
, type
, op
;
1298 char *k
, *v
, *o
, *p
;
1301 if (buf
== NULL
) return NULL
;
1303 type
= ASL_TYPE_MSG
;
1306 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1307 if (k
== NULL
) return NULL
;
1311 type
= ASL_TYPE_QUERY
;
1314 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1316 else if (tt
== TOKEN_INT
)
1318 /* Leading integer is a string length - skip it */
1320 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1321 if (k
== NULL
) return NULL
;
1324 msg
= calloc(1, sizeof(asl_msg_t
));
1325 if (msg
== NULL
) return NULL
;
1329 /* OPEN WORD [WORD [WORD]] CLOSE */
1332 op
= ASL_QUERY_OP_NULL
;
1334 if (tt
!= TOKEN_OPEN
)
1342 /* get op for query type */
1343 if (type
== ASL_TYPE_QUERY
)
1345 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
1346 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
1348 if (o
!= NULL
) free(o
);
1353 op
= _asl_msg_op_from_string(o
);
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
))
1361 if (k
!= NULL
) free(k
);
1366 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
1367 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1370 asl_set_query(msg
, k
, NULL
, op
);
1374 if (tt
== TOKEN_CLOSE
)
1376 asl_set_query(msg
, k
, NULL
, op
);
1378 else if (tt
== TOKEN_WORD
)
1380 asl_set_query(msg
, k
, v
, op
);
1384 if (k
!= NULL
) free(k
);
1385 if (v
!= NULL
) free(v
);
1390 if (k
!= NULL
) free(k
);
1391 if (v
!= NULL
) free(v
);
1393 if (tt
!= TOKEN_CLOSE
)
1395 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1396 if (k
== NULL
) break;
1398 if (tt
!= TOKEN_CLOSE
)
1407 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1408 if (k
== NULL
) break;
1415 asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
)
1417 uint32_t i
, len
, newlen
;
1420 if (list
== NULL
) return NULL
;
1421 if (list
->count
== 0) return NULL
;
1422 if (list
->msg
== NULL
) return NULL
;
1425 asprintf(&out
, "%u\n", list
->count
);
1426 if (out
== NULL
) return NULL
;
1427 *outlen
= strlen(out
) + 1;
1429 for (i
= 0; i
< list
->count
; i
++)
1432 msgbuf
= asl_msg_to_string(list
->msg
[i
], &len
);
1440 newlen
= *outlen
+ len
;
1441 out
= reallocf(out
, newlen
);
1448 memmove((out
+ *outlen
- 1), msgbuf
, len
);
1449 out
[newlen
- 2] = '\n';
1450 out
[newlen
- 1] = '\0';
1459 asl_search_result_t
*
1460 asl_list_from_string(const char *buf
)
1464 asl_search_result_t
*out
;
1467 if (buf
== NULL
) return NULL
;
1471 if (n
== 0) return NULL
;
1473 out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1474 if (out
== NULL
) return NULL
;
1476 out
->msg
= (asl_msg_t
**)calloc(n
, sizeof(asl_msg_t
*));
1477 if (out
->msg
== NULL
)
1483 for (i
= 0; i
< n
; i
++)
1485 p
= strchr(p
, '\n');
1488 aslresponse_free((aslresponse
)out
);
1494 m
= asl_msg_from_string(p
);
1497 aslresponse_free((aslresponse
)out
);
1509 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1513 if (a
->count
!= b
->count
) return 0;
1515 for (i
= 0; i
< a
->count
; i
++)
1517 j
= _asl_msg_index(b
, a
->key
[i
]);
1518 if (j
== (uint32_t)-1) return 0;
1520 if (a
->val
[i
] == NULL
)
1522 if (b
->val
[j
] != NULL
) return 0;
1526 if (b
->val
[j
] == NULL
) return 0;
1527 if (strcmp(a
->val
[i
], b
->val
[j
])) return 0;
1530 if (a
->type
== ASL_TYPE_QUERY
)
1532 if (a
->op
[i
] != b
->op
[j
]) return 0;
1540 _asl_isanumber(char *s
)
1544 if (s
== NULL
) return 0;
1547 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1549 if (s
[i
] == '\0') return 0;
1551 for (; s
[i
] != '\0'; i
++)
1553 if (!isdigit(s
[i
])) return 0;
1560 _asl_msg_basic_test(uint32_t op
, char *q
, char *m
, uint32_t n
)
1567 t
= op
& ASL_QUERY_OP_TRUE
;
1569 /* NULL value from query or message string fails */
1570 if ((q
== NULL
) || (m
== NULL
)) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1572 if (op
& ASL_QUERY_OP_REGEX
)
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;
1577 memset(&rex
, 0, sizeof(regex_t
));
1579 rflags
= REG_EXTENDED
| REG_NOSUB
;
1580 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1582 /* A bad reqular expression matches nothing */
1583 if (regcomp(&rex
, q
, rflags
) != 0) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1585 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1588 if (t
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp
!= 0);
1592 if (op
& ASL_QUERY_OP_NUMERIC
)
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
);
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
);
1608 default: return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1613 if (op
& ASL_QUERY_OP_CASEFOLD
)
1615 if (n
== 0) cmp
= strcasecmp(m
, q
);
1616 else cmp
= strncasecmp(m
, q
, n
);
1620 if (n
== 0) cmp
= strcmp(m
, q
);
1621 else cmp
= strncmp(m
, q
, n
);
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);
1634 return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1638 _asl_msg_test_substring(uint32_t op
, char *q
, char *m
)
1640 uint32_t t
, i
, d
, lm
, lq
, match
, newop
;
1642 t
= op
& ASL_QUERY_OP_TRUE
;
1645 if (m
!= NULL
) lm
= strlen(m
);
1648 if (q
!= NULL
) lq
= strlen(q
);
1650 /* NULL is a substring of any string */
1651 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
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
);
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;
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.
1665 newop
|= ASL_QUERY_OP_EQUAL
;
1669 for (i
= 0; i
<= d
; i
++)
1671 if (_asl_msg_basic_test(newop
, q
, m
+ i
, lq
) != 0)
1673 if (t
& ASL_QUERY_OP_EQUAL
) return 1;
1678 /* If the input test was for equality, no matches were found */
1679 if (t
& ASL_QUERY_OP_EQUAL
) return 0;
1681 /* The input test was for not equal. Return true if no matches were found */
1682 return (match
== 0);
1686 _asl_msg_test_prefix(uint32_t op
, char *q
, char *m
)
1690 t
= op
& ASL_QUERY_OP_TRUE
;
1693 if (m
!= NULL
) lm
= strlen(m
);
1696 if (q
!= NULL
) lq
= strlen(q
);
1698 /* NULL is a prefix of any string */
1699 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
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
);
1704 /* Compare two equal-length strings */
1705 return _asl_msg_basic_test(op
, q
, m
, lq
);
1709 _asl_msg_test_suffix(uint32_t op
, char *q
, char *m
)
1711 uint32_t lm
, lq
, d
, t
;
1713 t
= op
& ASL_QUERY_OP_TRUE
;
1716 if (m
!= NULL
) lm
= strlen(m
);
1719 if (q
!= NULL
) lq
= strlen(q
);
1721 /* NULL is a suffix of any string */
1722 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
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
);
1727 /* Compare two equal-length strings */
1729 return _asl_msg_basic_test(op
, q
, m
+ d
, lq
);
1733 * Splits out prefix, suffix, and substring tests.
1734 * Sends the rest to _asl_msg_basic_test().
1737 _asl_msg_test_expression(uint32_t op
, char *q
, char *m
)
1741 t
= op
& ASL_QUERY_OP_TRUE
;
1742 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1744 if (op
& ASL_QUERY_OP_PREFIX
)
1746 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
);
1747 return _asl_msg_test_prefix(op
, q
, m
);
1749 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
);
1751 return _asl_msg_basic_test(op
, q
, m
, 0);
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.
1760 _asl_msg_test_time_expression(uint32_t op
, char *q
, char *m
)
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
);
1768 tq
= asl_parse_time(q
);
1769 if (tq
< 0) return _asl_msg_test_expression(op
, q
, m
);
1771 tm
= asl_parse_time(m
);
1772 if (tm
< 0) return _asl_msg_test_expression(op
, q
, m
);
1774 t
= op
& ASL_QUERY_OP_TRUE
;
1778 case ASL_QUERY_OP_FALSE
:
1782 case ASL_QUERY_OP_EQUAL
:
1784 if (tm
== tq
) return 1;
1787 case ASL_QUERY_OP_GREATER
:
1789 if (tm
> tq
) return 1;
1792 case ASL_QUERY_OP_GREATER_EQUAL
:
1794 if (tm
>= tq
) return 1;
1797 case ASL_QUERY_OP_LESS
:
1799 if (tm
< tq
) return 1;
1802 case ASL_QUERY_OP_LESS_EQUAL
:
1804 if (tm
<= tq
) return 1;
1807 case ASL_QUERY_OP_NOT_EQUAL
:
1809 if (tm
!= tq
) return 1;
1812 case ASL_QUERY_OP_TRUE
:
1822 /* test a query against a message */
1824 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
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).
1834 for (i
= 0; i
< q
->count
; i
++)
1836 /* Find query key[i] in the message */
1837 j
= _asl_msg_index(m
, q
->key
[i
]);
1839 /* NULL op is meaningless, but we allow it to succeed */
1840 if (q
->op
== NULL
) continue;
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
)
1846 if (j
== (uint32_t)-1) return 0;
1850 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1851 if (t
== ASL_QUERY_OP_FALSE
)
1853 if (j
!= (uint32_t)-1) return 0;
1857 if (j
== (uint32_t)-1)
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;
1865 if (streq(q
->key
[i
], ASL_KEY_TIME
))
1867 cmp
= _asl_msg_test_time_expression(q
->op
[i
], q
->val
[i
], m
->val
[j
]);
1871 cmp
= _asl_msg_test_expression(q
->op
[i
], q
->val
[i
], m
->val
[j
]);
1874 if (cmp
== 0) return 0;
1881 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1883 if (a
== NULL
) return 0;
1884 if (b
== NULL
) return 0;
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
);
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.
1896 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
1899 int use_global_lock
;
1902 use_global_lock
= 0;
1903 asl
= (asl_client_t
*)ac
;
1906 asl
= _asl_open_default();
1907 if (asl
== NULL
) return -1;
1908 pthread_mutex_lock(&_asl_global
.lock
);
1909 use_global_lock
= 1;
1912 for (i
= 0; i
< asl
->fd_count
; i
++)
1914 if (asl
->fd_list
[i
] == fd
)
1916 /* update message format, time format, and text encoding */
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
);
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
);
1925 asl
->fd_encoding
[i
] = text_encoding
;
1927 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1932 if (asl
->fd_count
== 0)
1934 asl
->fd_list
= (int *)calloc(1, sizeof(int));
1935 asl
->fd_mfmt
= (char **)calloc(1, sizeof(char *));
1936 asl
->fd_tfmt
= (char **)calloc(1, sizeof(char *));
1937 asl
->fd_encoding
= (uint32_t *)calloc(1, sizeof(int));
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 *));
1944 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, (1 + asl
->fd_count
) * sizeof(uint32_t));
1947 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
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
);
1952 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
1954 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1958 asl
->fd_list
[asl
->fd_count
] = fd
;
1959 if (mfmt
!= NULL
) asl
->fd_mfmt
[asl
->fd_count
] = strdup(mfmt
);
1960 if (tfmt
!= NULL
) asl
->fd_tfmt
[asl
->fd_count
] = strdup(tfmt
);
1961 asl
->fd_encoding
[asl
->fd_count
] = text_encoding
;
1965 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1970 asl_add_log_file(aslclient ac
, int fd
)
1972 return asl_add_output(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
1976 * asl_remove_output: stop writing log messages to the given file descriptor
1979 asl_remove_output(aslclient ac
, int fd
)
1982 int x
, use_global_lock
;
1985 use_global_lock
= 0;
1986 asl
= (asl_client_t
*)ac
;
1989 asl
= _asl_open_default();
1990 if (asl
== NULL
) return -1;
1991 pthread_mutex_lock(&_asl_global
.lock
);
1992 use_global_lock
= 1;
1995 if (asl
->fd_count
== 0)
1997 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2002 for (i
= 0; i
< asl
->fd_count
; i
++)
2004 if (asl
->fd_list
[i
] == fd
)
2013 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2017 if (asl
->fd_mfmt
[x
] != NULL
) free(asl
->fd_mfmt
[x
]);
2018 if (asl
->fd_tfmt
[x
] != NULL
) free(asl
->fd_tfmt
[x
]);
2020 for (i
= x
+ 1; i
< asl
->fd_count
; i
++, x
++)
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
];
2025 asl
->fd_encoding
[x
] = asl
->fd_encoding
[i
];
2030 if (asl
->fd_count
== 0)
2033 asl
->fd_list
= NULL
;
2036 asl
->fd_mfmt
= NULL
;
2039 asl
->fd_tfmt
= NULL
;
2041 free(asl
->fd_encoding
);
2042 asl
->fd_encoding
= NULL
;
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 *));
2049 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, asl
->fd_count
* sizeof(uint32_t));
2051 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
2053 if (asl
->fd_list
!= NULL
)
2056 asl
->fd_list
= NULL
;
2059 if (asl
->fd_mfmt
!= NULL
)
2061 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
2063 asl
->fd_mfmt
= NULL
;
2066 if (asl
->fd_tfmt
!= NULL
)
2068 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
2070 asl
->fd_tfmt
= NULL
;
2073 if (asl
->fd_encoding
!= NULL
)
2075 free(asl
->fd_encoding
);
2076 asl
->fd_encoding
= NULL
;
2080 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2085 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2090 asl_remove_log_file(aslclient ac
, int fd
)
2092 return asl_remove_output(ac
, fd
);
2096 asl_set_filter(aslclient ac
, int f
)
2098 int last
, use_global_lock
;
2101 use_global_lock
= 0;
2102 asl
= (asl_client_t
*)ac
;
2105 asl
= _asl_open_default();
2106 if (asl
== NULL
) return -1;
2107 pthread_mutex_lock(&_asl_global
.lock
);
2108 use_global_lock
= 1;
2114 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
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
2124 asl_key(aslmsg a
, uint32_t n
)
2128 msg
= (asl_msg_t
*)a
;
2129 if (msg
== NULL
) return NULL
;
2131 if (n
>= msg
->count
) return NULL
;
2136 * asl_new: create a new log message.
2139 asl_new(uint32_t type
)
2144 msg
= calloc(1, sizeof(asl_msg_t
));
2145 if (msg
== NULL
) return NULL
;
2148 if (type
== ASL_TYPE_QUERY
) return (aslmsg
)msg
;
2151 * Defaut attributes are:
2163 msg
->key
= calloc(msg
->count
, sizeof(char *));
2164 if (msg
->key
== NULL
)
2170 msg
->val
= calloc(msg
->count
, sizeof(char *));
2171 if (msg
->val
== NULL
)
2179 msg
->key
[i
] = strdup(ASL_KEY_TIME
);
2180 if (msg
->key
[i
] == NULL
)
2187 msg
->key
[i
] = strdup(ASL_KEY_HOST
);
2188 if (msg
->key
[i
] == NULL
)
2195 msg
->key
[i
] = strdup(ASL_KEY_SENDER
);
2196 if (msg
->key
[i
] == NULL
)
2203 msg
->key
[i
] = strdup(ASL_KEY_PID
);
2204 if (msg
->key
[i
] == NULL
)
2211 msg
->key
[i
] = strdup(ASL_KEY_UID
);
2212 if (msg
->key
[i
] == NULL
)
2219 msg
->key
[i
] = strdup(ASL_KEY_GID
);
2220 if (msg
->key
[i
] == NULL
)
2227 msg
->key
[i
] = strdup(ASL_KEY_LEVEL
);
2228 if (msg
->key
[i
] == NULL
)
2235 msg
->key
[i
] = strdup(ASL_KEY_MSG
);
2236 if (msg
->key
[i
] == NULL
)
2246 * asl_get: get attribute values from a message
2248 * key: attribute key
2249 * returns the attribute value
2250 * returns NULL if the message does not contain the key
2253 asl_get(aslmsg a
, const char *key
)
2258 msg
= (asl_msg_t
*)a
;
2260 if (msg
== NULL
) return NULL
;
2262 i
= _asl_msg_index(msg
, key
);
2263 if (i
== (uint32_t)-1) return NULL
;
2267 #endif /* BUILDING_VARIANT */
2270 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
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
2278 asl_vlog(aslclient ac
, aslmsg a
, int level
, const char *format
, va_list ap
)
2280 int status
, saved_errno
;
2282 char *str
, *fmt
, *estr
;
2283 uint32_t i
, len
, elen
, expand
, my_msg
;
2286 asl
= (asl_client_t
*)ac
;
2290 * Initialize _asl_global so that asl_new will have global data.
2291 * Not strictly necessary, but helps performance.
2293 asl
= _asl_open_default();
2294 if (asl
== NULL
) return -1;
2297 saved_errno
= errno
;
2299 if (format
== NULL
) return -1;
2301 msg
= (asl_msg_t
*)a
;
2307 msg
= asl_new(ASL_TYPE_MSG
);
2308 if (msg
== NULL
) return -1;
2311 if (msg
->type
!= ASL_TYPE_MSG
) return -1;
2313 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
2314 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
2316 /* insert strerror for %m */
2319 estr
= strdup(strerror(saved_errno
));
2322 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2330 elen
= strlen(estr
);
2332 for (i
= 0; format
[i
] != '\0'; i
++)
2334 if (format
[i
] == '%')
2336 if (format
[i
+1] == '\0') len
++;
2337 else if (format
[i
+1] == 'm')
2353 fmt
= (char *)format
;
2357 fmt
= malloc(len
+ 1);
2360 if (estr
!= NULL
) free(estr
);
2366 for (i
= 0; format
[i
] != '\0'; i
++)
2368 if (format
[i
] == '%')
2370 if (format
[i
+1] == '\0')
2373 else if (format
[i
+1] == 'm')
2375 memcpy(fmt
+len
, estr
, elen
);
2381 fmt
[len
++] = format
[i
++];
2382 fmt
[len
++] = format
[i
];
2385 else fmt
[len
++] = format
[i
];
2391 if (estr
!= NULL
) free(estr
);
2393 vasprintf(&str
, fmt
, ap
);
2394 if (expand
!= 0) free(fmt
);
2398 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2402 status
= _asl_send_level_message(ac
, (aslmsg
)msg
, level
, str
);
2405 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2410 * asl_log: log a message with a particular log level
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
2417 asl_log(aslclient ac
, aslmsg a
, int level
, const char *format
, ...)
2422 if (format
== NULL
) return -1;
2424 va_start(ap
, format
);
2425 status
= asl_vlog(ac
, a
, level
, format
, ap
);
2431 #ifndef BUILDING_VARIANT
2434 _asl_level_string(int level
)
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
;
2448 * format a message for printing
2449 * out parameter len returns string length including trailing NUL
2452 asl_format_message(aslmsg msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
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
;
2461 if (msg
== NULL
) return NULL
;
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
;
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
;
2481 out
= _asl_msg_to_string_time_fmt((asl_msg_t
*)msg
, len
, tf
);
2487 mstr
= asl_get(msg
, ASL_KEY_MSG
);
2488 if (mstr
== NULL
) return NULL
;
2490 _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2491 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2496 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
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 */
2503 v
= asl_get(msg
, ASL_KEY_TIME
);
2504 tstr
= _asl_time_string(tf
, v
);
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
);
2511 rprc
= asl_get(msg
, ASL_KEY_REF_PROC
);
2512 rpid
= asl_get(msg
, ASL_KEY_REF_PID
);
2518 lstr
= asl_get(msg
, ASL_KEY_LEVEL
);
2519 if (lstr
!= NULL
) level
= atoi(lstr
);
2524 _asl_append_string(&out
, len
, "0", ASL_ENCODE_NONE
, 0);
2528 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2532 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
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);
2537 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
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);
2542 if ((pstr
!= NULL
) && (strcmp(pstr
, "-1")))
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);
2549 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, " (", ASL_ENCODE_NONE
, 0);
2551 if (rprc
!= NULL
) _asl_append_string(&out
, len
, rprc
, text_encoding
, 0);
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);
2559 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, ")", ASL_ENCODE_NONE
, 0);
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);
2568 _asl_append_string(&out
, len
, ": ", ASL_ENCODE_NONE
, 0);
2570 if (mstr
!= NULL
) _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2572 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2578 _asl_append_string(&out
, len
, "\t<dict>\n", ASL_ENCODE_NONE
, 0);
2580 for (i
= 0; i
< msg
->count
; i
++)
2582 if (asl_is_utf8(msg
->key
[i
]) == 1)
2584 _asl_append_xml_tag(&out
, len
, XML_TAG_KEY
, msg
->key
[i
]);
2585 if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
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
);
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
]);
2599 _asl_append_string(&out
, len
, "\t</dict>\n", ASL_ENCODE_NONE
, 0);
2606 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2622 if (out
!= NULL
) free(out
);
2628 for (j
= i
; mfmt
[j
] != '\0'; j
++)
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
];
2635 if (c
[0] == '\0') break;
2637 k
= reallocf(k
, l
+ 1);
2640 if (out
!= NULL
) free(out
);
2649 if (paren
== 1) j
++;
2653 v
= asl_get(msg
, k
);
2656 if (!strcmp(k
, ASL_KEY_TIME
))
2658 tstr
= _asl_time_string(tf
, v
);
2659 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2660 if (tstr
!= NULL
) free(tstr
);
2664 _asl_append_string(&out
, len
, (char *)v
, ASL_ENCODE_NONE
, 0);
2671 if (mfmt
[i
] == '\\')
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);
2686 else if (isdigit(mfmt
[i
]))
2688 oval
= mfmt
[i
] - '0';
2689 if (isdigit(mfmt
[i
+1]))
2692 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2693 if (isdigit(mfmt
[i
+1]))
2696 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2700 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2705 if (mfmt
[i
] == '\0') break;
2707 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2710 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2716 * asl_send (internal version): send a message
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.
2719 * returns 0 for success, non-zero for failure
2721 __private_extern__
int
2722 _asl_send_level_message(aslclient ac
, aslmsg msg
, int level
, const char *message
)
2724 char *str
, *out_raw
;
2726 uint32_t i
, len
, outlen
, lmask
, outstatus
, filter
, check
, senderx
, facilityx
;
2731 struct timeval tval
;
2732 int status
, rc_filter
;
2734 int use_global_lock
;
2735 asl_msg_t
*mt
, *tmp_msg
;
2736 char hname
[_POSIX_HOST_NAME_MAX
];
2737 kern_return_t kstatus
;
2739 use_global_lock
= 0;
2740 asl
= (asl_client_t
*)ac
;
2743 asl
= _asl_open_default();
2744 if (asl
== NULL
) return -1;
2745 use_global_lock
= 1;
2748 if (msg
== NULL
) return 0;
2750 val
= asl_get(msg
, ASL_KEY_LEVEL
);
2751 if (val
!= NULL
) level
= atoi(val
);
2753 lmask
= ASL_FILTER_MASK(level
);
2755 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
2757 pthread_mutex_lock(&_asl_global
.lock
);
2759 if (_asl_global
.rc_change_token
>= 0)
2761 /* initialize or re-check process-specific and master filters */
2763 status
= notify_check(_asl_global
.rc_change_token
, &check
);
2764 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
2766 if (_asl_global
.master_token
>= 0)
2769 status
= notify_get_state(_asl_global
.master_token
, &v64
);
2770 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
2773 if (_asl_global
.notify_token
>= 0)
2776 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
2777 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
2782 pthread_mutex_unlock(&_asl_global
.lock
);
2785 filter
= asl
->filter
;
2788 /* master filter overrides local filter */
2789 if (_asl_global
.master_filter
!= 0)
2791 filter
= _asl_global
.master_filter
;
2795 /* process-specific filter overrides local and master */
2796 if (_asl_global
.proc_filter
!= 0)
2798 filter
= _asl_global
.proc_filter
;
2803 * Copy the message to tmp_msg to make setting values thread-safe
2805 tmp_msg
= calloc(1, sizeof(asl_msg_t
));
2806 if (tmp_msg
== NULL
) return -1;
2808 tmp_msg
->type
= ASL_TYPE_MSG
;
2810 mt
= (asl_msg_t
*)msg
;
2811 for (i
= 0; i
< mt
->count
; i
++)
2813 asl_set(tmp_msg
, mt
->key
[i
], mt
->val
[i
]);
2817 * Set Level and Message from parameters.
2819 if (message
!= NULL
) asl_set(tmp_msg
, ASL_KEY_MSG
, message
);
2820 asl_set(tmp_msg
, ASL_KEY_LEVEL
, _asl_level_string(level
));
2823 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here
2826 memset(&tval
, 0, sizeof(struct timeval
));
2828 status
= gettimeofday(&tval
, NULL
);
2831 asprintf(&str
, "%lu", tval
.tv_sec
);
2834 asl_set(tmp_msg
, ASL_KEY_TIME
, str
);
2839 asprintf(&str
, "%lu", tval
.tv_usec
* 1000);
2842 asl_set(tmp_msg
, ASL_KEY_TIME_NSEC
, str
);
2850 asprintf(&str
, "%lu", tick
);
2853 asl_set(tmp_msg
, ASL_KEY_TIME
, str
);
2859 memset(&hname
, 0, _POSIX_HOST_NAME_MAX
);
2860 if (gethostname(hname
, _POSIX_HOST_NAME_MAX
) == 0)
2862 asl_set(tmp_msg
, ASL_KEY_HOST
, hname
);
2866 asprintf(&str
, "%u", getpid());
2869 asl_set(tmp_msg
, ASL_KEY_PID
, str
);
2874 asprintf(&str
, "%d", getuid());
2877 asl_set(tmp_msg
, ASL_KEY_UID
, str
);
2882 asprintf(&str
, "%u", getgid());
2885 asl_set(tmp_msg
, ASL_KEY_GID
, str
);
2889 senderx
= (uint32_t)-1;
2890 facilityx
= (uint32_t)-1;
2892 for (i
= 0; (i
< tmp_msg
->count
) && ((senderx
== (uint32_t)-1) || (facilityx
== (uint32_t)-1)); i
++)
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
;
2900 * Set Sender if needed
2902 if ((senderx
== (uint32_t)-1) || (tmp_msg
->val
[senderx
] == NULL
))
2904 if ((ac
!= NULL
) && (ac
->name
!= NULL
))
2906 /* Use the Sender name from the client handle */
2907 asl_set(tmp_msg
, ASL_KEY_SENDER
, ac
->name
);
2911 /* Get the value for ASL_KEY_SENDER from cache */
2912 if (_asl_global
.sender
== NULL
)
2914 name
= *(*_NSGetArgv());
2917 x
= strrchr(name
, '/');
2921 pthread_mutex_lock(&_asl_global
.lock
);
2923 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
2924 pthread_mutex_unlock(&_asl_global
.lock
);
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");
2936 if ((facilityx
== (uint32_t)-1) || (tmp_msg
->val
[facilityx
] == NULL
))
2938 if ((ac
!= NULL
) && (ac
->facility
!= NULL
))
2940 /* Use the Facility name from the client handle */
2941 asl_set(tmp_msg
, ASL_KEY_FACILITY
, ac
->facility
);
2945 /* Set "ASLOption store" if remote control is active */
2948 val
= asl_get(msg
, ASL_KEY_OPTION
);
2951 asl_set(tmp_msg
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
2956 asprintf(&str
, "%s %s", ASL_OPT_STORE
, val
);
2959 asl_set(tmp_msg
, ASL_KEY_OPTION
, str
);
2968 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
2970 if ((filter
!= 0) && ((filter
& lmask
) != 0))
2973 out_raw
= asl_msg_to_string(tmp_msg
, &len
);
2975 if ((out_raw
!= NULL
) && (len
!= 0))
2977 /* send a mach message to syslogd */
2979 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&out
, outlen
+ 1, TRUE
);
2980 if (kstatus
== KERN_SUCCESS
)
2982 memset(out
, 0, outlen
+ 1);
2983 snprintf((char *)out
, outlen
, "%10u %s", len
, out_raw
);
2987 pthread_mutex_lock(&(_asl_global
.port_lock
));
2989 if (_asl_global
.server_port
== MACH_PORT_NULL
)
2991 _asl_global
.port_count
= 0;
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
;
2998 pthread_mutex_unlock(&(_asl_global
.port_lock
));
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);
3003 if (kstatus
== KERN_SUCCESS
) outstatus
= 0;
3012 /* write to file descriptors */
3013 for (i
= 0; i
< asl
->fd_count
; i
++)
3015 if (asl
->fd_list
[i
] < 0) continue;
3018 out
= asl_format_message(tmp_msg
, asl
->fd_mfmt
[i
], asl
->fd_tfmt
[i
], asl
->fd_encoding
[i
], &len
);
3019 if (out
== NULL
) continue;
3021 status
= write(asl
->fd_list
[i
], out
, len
- 1);
3024 asl
->fd_list
[i
] = -1;
3031 asl_free((aslmsg
)tmp_msg
);
3033 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
3039 * asl_send: send a message
3040 * returns 0 for success, non-zero for failure
3043 asl_send(aslclient ac
, aslmsg msg
)
3045 return _asl_send_level_message(ac
, msg
, ASL_LEVEL_DEBUG
, NULL
);
3049 asl_msg_string(aslmsg a
)
3053 return asl_msg_to_string((asl_msg_t
*)a
, &len
);
3057 * asl_free: free a message
3058 * msg: an aslmsg to free
3066 msg
= (asl_msg_t
*)a
;
3068 if (msg
== NULL
) return;
3070 for (i
= 0; i
< msg
->count
; i
++)
3072 if (msg
->key
[i
] != NULL
) free(msg
->key
[i
]);
3073 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3078 if (msg
->key
!= NULL
) free(msg
->key
);
3079 if (msg
->val
!= NULL
) free(msg
->val
);
3080 if (msg
->op
!= NULL
) free(msg
->op
);
3087 * Called if there's a malloc error while manipulating a message in asl_set_query.
3088 * Cleans up the key, val, and op fields, sets count to zero.
3091 _asl_clear_msg(asl_msg_t
*msg
)
3095 if (msg
== NULL
) return;
3097 for (i
= 0; i
< msg
->count
; i
++)
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
]);
3103 if (msg
->key
!= NULL
) free(msg
->key
);
3104 if (msg
->val
!= NULL
) free(msg
->val
);
3105 if (msg
->op
!= NULL
) free(msg
->op
);
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.
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
3125 asl_set_query(aslmsg a
, const char *key
, const char *val
, uint32_t op
)
3131 msg
= (asl_msg_t
*)a
;
3133 if (msg
== NULL
) return 0;
3134 if (key
== NULL
) return -1;
3138 if ((streq(key
, ASL_KEY_MSG
)) && (val
!= NULL
))
3140 /* strip trailing newlines */
3142 if (dv
== NULL
) return -1;
3146 while ((len
> 0) && (dv
[i
] == '\n'))
3153 else if (streq(key
, ASL_KEY_LEVEL
))
3155 if (val
== NULL
) return -1;
3156 if (val
[0] == '\0') return -1;
3157 if ((val
[0] >= '0') && (val
[0] <= '9'))
3160 asprintf(&dv
, "%d", i
);
3161 if (dv
== NULL
) return -1;
3163 else if (!strcasecmp(val
, ASL_STRING_EMERG
))
3166 if (dv
== NULL
) return -1;
3168 else if (!strcasecmp(val
, ASL_STRING_ALERT
))
3171 if (dv
== NULL
) return -1;
3173 else if (!strcasecmp(val
, ASL_STRING_CRIT
))
3176 if (dv
== NULL
) return -1;
3178 else if (!strcasecmp(val
, ASL_STRING_ERR
))
3181 if (dv
== NULL
) return -1;
3183 else if (!strcasecmp(val
, ASL_STRING_WARNING
))
3186 if (dv
== NULL
) return -1;
3188 else if (!strcasecmp(val
, ASL_STRING_NOTICE
))
3191 if (dv
== NULL
) return -1;
3193 else if (!strcasecmp(val
, ASL_STRING_INFO
))
3196 if (dv
== NULL
) return -1;
3198 else if (!strcasecmp(val
, ASL_STRING_DEBUG
))
3201 if (dv
== NULL
) return -1;
3206 if ((dv
== NULL
) && (val
!= NULL
))
3209 if (dv
== NULL
) return -1;
3212 for (i
= 0; i
< msg
->count
; i
++)
3214 if (msg
->key
[i
] == NULL
) continue;
3216 if ((msg
->type
!= ASL_TYPE_QUERY
) && (streq(msg
->key
[i
], key
)))
3218 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3220 if (val
!= NULL
) msg
->val
[i
] = dv
;
3221 if (msg
->op
!= NULL
) msg
->op
[i
] = op
;
3226 if (msg
->count
== 0)
3228 msg
->key
= (char **)calloc(1, sizeof(char *));
3229 if (msg
->key
== NULL
)
3231 _asl_clear_msg(msg
);
3235 msg
->val
= (char **)calloc(1, sizeof(char *));
3236 if (msg
->val
== NULL
)
3238 _asl_clear_msg(msg
);
3242 if (msg
->type
== ASL_TYPE_QUERY
)
3244 msg
->op
= (uint32_t *)calloc(1, sizeof(uint32_t));
3245 if (msg
->op
== NULL
)
3247 _asl_clear_msg(msg
);
3254 msg
->key
= (char **)reallocf(msg
->key
, (msg
->count
+ 1) * sizeof(char *));
3255 if (msg
->key
== NULL
)
3257 _asl_clear_msg(msg
);
3261 msg
->val
= (char **)reallocf(msg
->val
, (msg
->count
+ 1) * sizeof(char *));
3262 if (msg
->val
== NULL
)
3264 _asl_clear_msg(msg
);
3268 if (msg
->type
== ASL_TYPE_QUERY
)
3270 msg
->op
= (uint32_t *)reallocf(msg
->op
, (msg
->count
+ 1) * sizeof(uint32_t));
3271 if (msg
->op
== NULL
)
3273 _asl_clear_msg(msg
);
3282 if (dv
!= NULL
) free(dv
);
3283 _asl_clear_msg(msg
);
3287 msg
->key
[msg
->count
] = dk
;
3288 msg
->val
[msg
->count
] = dv
;
3289 if (msg
->op
!= NULL
) msg
->op
[msg
->count
] = op
;
3296 * asl_set: set attributes of a message
3298 * key: attribute key
3299 * value: attribute value
3300 * returns 0 for success, non-zero for failure
3303 asl_set(aslmsg msg
, const char *key
, const char *val
)
3305 return asl_set_query(msg
, key
, val
, 0);
3309 * asl_unset: remove attributes of a message
3311 * key: attribute key
3312 * returns 0 for success, non-zero for failure
3315 asl_unset(aslmsg a
, const char *key
)
3320 msg
= (asl_msg_t
*)a
;
3322 if (msg
== NULL
) return 0;
3323 if (key
== NULL
) return 0;
3325 for (i
= 0; i
< msg
->count
; i
++)
3327 if (msg
->key
[i
] == NULL
) continue;
3329 if (streq(msg
->key
[i
], key
))
3332 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3334 for (j
= i
+ 1; j
< msg
->count
; j
++, i
++)
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
];
3343 if (msg
->count
== 0)
3351 if (msg
->op
!= NULL
) free(msg
->op
);
3356 msg
->key
= (char **)reallocf(msg
->key
, msg
->count
* sizeof(char *));
3357 if (msg
->key
== NULL
) return -1;
3359 msg
->val
= (char **)reallocf(msg
->val
, msg
->count
* sizeof(char *));
3360 if (msg
->val
== NULL
) return -1;
3362 if (msg
->op
!= NULL
)
3364 msg
->op
= (uint32_t *)reallocf(msg
->op
, msg
->count
* sizeof(uint32_t));
3365 if (msg
->op
== NULL
) return -1;
3377 * asl_search: Search for messages matching the criteria described
3378 * by the aslmsg. The caller should set the attributes to match using
3379 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
3380 * used for attributes set with asl_set().
3382 * returns: a set of messages that can be iterated over using aslresp_next(),
3383 * and the values can be retrieved using aslresp_get.
3386 asl_search(aslclient ac
, aslmsg a
)
3388 asl_search_result_t query
, *out
;
3389 asl_msg_t
*q
, *qlist
[1];
3391 uint64_t last_id
, start_id
;
3394 if (a
== NULL
) return NULL
;
3398 /* check for "ASLMessageId >[=] n" and set start_id */
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
))
3403 if (q
->op
[x
] & ASL_QUERY_OP_EQUAL
) start_id
= atoi(q
->val
[x
]);
3404 else start_id
= atoi(q
->val
[x
]) + 1;
3408 status
= asl_store_open_read(NULL
, &store
);
3409 if (status
!= 0) return NULL
;
3410 if (store
== NULL
) return NULL
;
3416 memset(&query
, 0, sizeof(asl_search_result_t
));
3420 status
= asl_store_match(store
, &query
, &out
, &last_id
, start_id
, 0, 1);
3421 asl_store_close(store
);
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
3432 aslresponse_next(aslresponse r
)
3434 asl_search_result_t
*res
;
3437 res
= (asl_search_result_t
*)r
;
3438 if (res
== NULL
) return NULL
;
3440 if (res
->curr
>= res
->count
) return NULL
;
3441 m
= res
->msg
[res
->curr
];
3448 * aslresponse_free: Free a response returned from asl_search()
3449 * a: a response returned from asl_search()
3452 aslresponse_free(aslresponse r
)
3454 asl_search_result_t
*res
;
3457 res
= (asl_search_result_t
*)r
;
3458 if (res
== NULL
) return;
3460 for (i
= 0; i
< res
->count
; i
++) asl_free(res
->msg
[i
]);
3466 asl_syslog_faciliy_name_to_num(const char *name
)
3468 if (name
== NULL
) return -1;
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
;
3500 asl_syslog_faciliy_num_to_name(int n
)
3502 if (n
< 0) return NULL
;
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";
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)
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]?$"
3548 #define SECONDS_PER_MINUTE 60
3549 #define SECONDS_PER_HOUR 3600
3550 #define SECONDS_PER_DAY 86400
3551 #define SECONDS_PER_WEEK 604800
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.
3560 * The MTH_LAST array maps the last letter to a number.
3562 static const int8_t MTH_LAST
[] = {-1, 1, 11, -1, -1, -1, 7, -1, -1, -1, -1, 6, -1, 5, -1, 8, -1, 3, -1, 9, -1, 10, -1, -1, 4, -1};
3571 if (s
[2] > 90) v8
= s
[2] - 'a';
3572 else v8
= s
[2] - 'A';
3574 if ((v8
< 0) || (v8
> 25)) return -1;
3577 if (v8
< 0) return -1;
3580 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
3581 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
3586 asl_parse_time(const char *in
)
3588 int len
, y
, status
, rflags
;
3590 time_t tick
, delta
, factor
;
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;
3598 if (in
== NULL
) return -1;
3600 rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
3602 if (init_canon
== 0)
3604 memset(&rex_canon
, 0, sizeof(regex_t
));
3605 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
3606 if (status
!= 0) return -1;
3610 if (init_ctime
== 0)
3612 memset(&rex_ctime
, 0, sizeof(regex_t
));
3613 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
3614 if (status
!= 0) return -1;
3620 memset(&rex_abs
, 0, sizeof(regex_t
));
3621 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
3622 if (status
!= 0) return -1;
3628 memset(&rex_rel
, 0, sizeof(regex_t
));
3629 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
3630 if (status
!= 0) return -1;
3634 len
= strlen(in
) + 1;
3636 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
3639 * Absolute time (number of seconds since the epoch)
3642 if (str
== NULL
) return -1;
3644 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
3651 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
3654 * Reletive time (number of seconds before or after right now)
3657 if (str
== NULL
) return -1;
3661 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
3665 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
3668 factor
= SECONDS_PER_MINUTE
;
3670 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
3673 factor
= SECONDS_PER_HOUR
;
3675 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
3678 factor
= SECONDS_PER_DAY
;
3680 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
3683 factor
= SECONDS_PER_WEEK
;
3687 delta
= factor
* atol(str
);
3694 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
3696 memset(&t
, 0, sizeof(struct tm
));
3698 if (str
== NULL
) return -1;
3704 t
.tm_year
= atoi(x
) - 1900;
3710 t
.tm_mon
= atoi(x
) - 1;
3716 t
.tm_mday
= atoi(x
);
3719 for (x
= p
+ 1; *x
== ' '; x
++);
3722 t
.tm_hour
= atoi(x
);
3739 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
3741 /* We assume it's in the current year */
3742 memset(&t
, 0, sizeof(struct tm
));
3744 gmtime_r(&tick
, &t
);
3747 memset(&t
, 0, sizeof(struct tm
));
3749 if (str
== NULL
) return -1;
3752 t
.tm_mon
= _month_num(str
);
3753 if (t
.tm_mon
< 0) return -1;
3755 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
3758 t
.tm_mday
= atoi(x
);
3761 for (x
= p
+ 1; *x
== ' '; x
++);
3764 t
.tm_hour
= atoi(x
);
3785 #endif /* BUILDING_VARIANT */