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>
52 #define streq(A, B) (strcmp(A, B) == 0)
53 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
55 #ifndef ASL_QUERY_OP_FALSE
56 #define ASL_QUERY_OP_FALSE 0
59 #define forever for(;;)
79 #define XML_TAG_STRING 1
80 #define XML_TAG_DATA 2
82 #define FETCH_BATCH 256
85 time_t asl_parse_time(const char *);
86 const char *asl_syslog_faciliy_num_to_name(int n
);
87 __private_extern__ asl_client_t
*_asl_open_default();
88 __private_extern__
int _asl_send_level_message(aslclient ac
, aslmsg msg
, int level
, const char *message
);
91 uint32_t notify_register_plain(const char *name
, int *out_token
);
94 int asl_is_utf8(const char *str
);
95 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
97 /* fork handling in syslog.c */
98 extern void _syslog_fork_child();
100 /* character encoding lengths */
101 static const uint8_t char_encode_len
[128] =
103 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
104 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
105 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
106 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3
109 static const char *cvis_7_13
= "abtnvfr";
117 uint64_t proc_filter
;
118 uint64_t master_filter
;
120 mach_port_t server_port
;
122 pthread_mutex_t lock
;
123 pthread_mutex_t port_lock
;
127 #ifndef BUILDING_VARIANT
128 __private_extern__ _asl_global_t _asl_global
= {0, -1, -1, -1, 0LL, 0LL, 0, MACH_PORT_NULL
, NULL
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, NULL
};
130 #define ASL_SERVICE_NAME "com.apple.system.logger"
133 * Called from the child process inside fork() to clean up
134 * inherited state from the parent process.
136 * NB. A lock isn't required, since we're single threaded in this call.
138 __private_extern__
void
141 _asl_global
.notify_count
= 0;
142 _asl_global
.rc_change_token
= -1;
143 _asl_global
.master_token
= -1;
144 _asl_global
.notify_token
= -1;
146 _asl_global
.port_count
= 0;
147 _asl_global
.server_port
= MACH_PORT_NULL
;
149 /* clean up in syslog.c */
150 _syslog_fork_child();
154 _asl_notify_open(int do_lock
)
160 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
162 _asl_global
.notify_count
++;
164 if (_asl_global
.notify_token
!= -1)
166 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
170 if (_asl_global
.rc_change_token
== -1)
172 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
173 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
176 if (_asl_global
.master_token
== -1)
178 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
179 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
184 if (euid
== 0) asprintf(¬ify_name
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, getpid());
185 else asprintf(¬ify_name
, "user.uid.%d.syslog.%d", euid
, getpid());
187 if (notify_name
!= NULL
)
189 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
191 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
194 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
196 if (_asl_global
.notify_token
== -1) return -1;
203 pthread_mutex_lock(&_asl_global
.lock
);
205 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
207 if (_asl_global
.notify_count
> 0)
209 pthread_mutex_unlock(&_asl_global
.lock
);
213 if (_asl_global
.rc_change_token
> 0) notify_cancel(_asl_global
.rc_change_token
);
214 _asl_global
.rc_change_token
= -1;
216 if (_asl_global
.master_token
> 0) notify_cancel(_asl_global
.master_token
);
217 _asl_global
.master_token
= -1;
219 if (_asl_global
.notify_token
> 0) notify_cancel(_asl_global
.notify_token
);
220 _asl_global
.notify_token
= -1;
222 pthread_mutex_unlock(&_asl_global
.lock
);
226 _asl_get_global_server_port()
228 kern_return_t kstatus
;
230 pthread_mutex_lock(&(_asl_global
.port_lock
));
232 if (_asl_global
.server_port
== MACH_PORT_NULL
)
234 _asl_global
.port_count
= 0;
236 kstatus
= bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &_asl_global
.server_port
);
237 if (kstatus
== KERN_SUCCESS
) _asl_global
.port_count
= 1;
238 else _asl_global
.server_port
= MACH_PORT_NULL
;
242 _asl_global
.port_count
++;
245 pthread_mutex_unlock(&(_asl_global
.port_lock
));
249 _asl_release_global_server_port()
251 pthread_mutex_lock(&(_asl_global
.port_lock
));
253 if (_asl_global
.port_count
> 0) _asl_global
.port_count
--;
254 if (_asl_global
.port_count
== 0)
256 mach_port_deallocate(mach_task_self(), _asl_global
.server_port
);
257 _asl_global
.server_port
= MACH_PORT_NULL
;
260 pthread_mutex_unlock(&(_asl_global
.port_lock
));
264 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
269 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
280 _asl_get_global_server_port();
286 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
290 asl
->name
= strdup(ident
);
291 if (asl
->name
== NULL
)
293 if (asl
->sock
>= 0) close(asl
->sock
);
300 name
= *(*_NSGetArgv());
303 x
= strrchr(name
, '/');
306 asl
->name
= strdup(x
);
307 if (asl
->name
== NULL
)
309 if (asl
->sock
>= 0) close(asl
->sock
);
316 asl
->facility
= NULL
;
317 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
318 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
319 if (asl
->facility
== NULL
)
321 if (asl
->sock
>= 0) close(asl
->sock
);
326 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
328 if (asl
->options
& ASL_OPT_STDERR
) asl_add_output((aslclient
)asl
, fileno(stderr
), ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
330 return (aslclient
)asl
;
334 asl_close(aslclient ac
)
339 asl
= (asl_client_t
*)ac
;
340 if (asl
== NULL
) return;
342 if (asl
->sock
>= 0) close(asl
->sock
);
344 pthread_mutex_lock(&(_asl_global
.port_lock
));
346 if (_asl_global
.port_count
> 0) _asl_global
.port_count
--;
347 if (_asl_global
.port_count
== 0)
349 mach_port_deallocate(mach_task_self(), _asl_global
.server_port
);
350 _asl_global
.server_port
= MACH_PORT_NULL
;
353 pthread_mutex_unlock(&(_asl_global
.port_lock
));
355 if (asl
->name
!= NULL
) free(asl
->name
);
356 if (asl
->facility
!= NULL
) free(asl
->facility
);
357 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_close();
358 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
360 if (asl
->fd_mfmt
!= NULL
)
362 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
366 if (asl
->fd_tfmt
!= NULL
)
368 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
372 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
374 memset(asl
, 0, sizeof(asl_client_t
));
378 __private_extern__ asl_client_t
*
381 if (_asl_global
.asl
!= NULL
) return _asl_global
.asl
;
383 pthread_mutex_lock(&_asl_global
.lock
);
384 if (_asl_global
.asl
!= NULL
)
386 pthread_mutex_unlock(&_asl_global
.lock
);
387 return _asl_global
.asl
;
391 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
392 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
393 * which locks _asl_global.lock.
395 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
397 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
398 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
400 /* Now call _asl_notify_open(0) to finish the work */
403 pthread_mutex_unlock(&_asl_global
.lock
);
405 return _asl_global
.asl
;
409 _asl_msg_index(asl_msg_t
*msg
, const char *k
)
413 if (msg
== NULL
) return (uint32_t)-1;
414 if (k
== NULL
) return (uint32_t)-1;
416 for (i
= 0; i
< msg
->count
; i
++)
418 if (msg
->key
[i
] == NULL
) continue;
419 if (streq(msg
->key
[i
], k
)) return i
;
426 _asl_encode_char(char **m
, uint32_t *x
, uint32_t c
, uint32_t encode
, uint32_t encode_space
)
435 /* NUL is not allowed */
438 /* Meta chars get \M prefix */
441 /* except meta-space, which is \240 */
461 /* space is either ' ' or \s */
464 if (encode_space
== 0)
480 if ((meta
== 0) && (c
== 92))
489 /* [ and ] are escaped in ASL encoding */
490 if ((encode
== ASL_ENCODE_ASL
) && (meta
== 0) && ((c
== 91) || (c
== 93)))
515 /* 33-126 are printable (add a '-' prefix for meta) */
516 if ((c
>= 33) && (c
<= 126))
530 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
531 if ((meta
== 0) && (c
>= 7) && (c
<= 13))
534 *p
++ = cvis_7_13
[c
- 7];
540 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
541 if ((c
>= 0) && (c
<= 31))
560 _asl_append_string(char **m
, uint32_t *x
, const char *s
, uint32_t encode
, uint32_t escspace
)
562 uint32_t i
, n
, spextra
;
566 if (m
== NULL
) return;
567 if (x
== NULL
) return;
568 if (s
== NULL
) return;
570 if (encode
== ASL_ENCODE_NONE
)
572 /* no encoding - just allocate enough space and copy the string */
584 *m
= reallocf(*m
, n
+ (*x
));
587 if (*m
== NULL
) return;
589 memcpy((*m
) + (*x
) - 1, s
, n
+ 1);
594 else if (encode
== ASL_ENCODE_SAFE
)
597 * Minor encoding to reduce the likelyhood of spoof attacks.
599 * - append a tab after newlines
600 * - translate \r to newline & append a tab
601 * - map backspace to ^H
603 * Note that there may be UTF-8 characters that could be used in a spoof
604 * attack that we don't check. Caveat Reador.
607 for (i
= 0; s
[i
] != '\0'; i
++)
611 if ((c
== 10) || (c
== 13) || (c
== 8)) n
++;
623 *m
= reallocf(*m
, n
+ (*x
));
626 if (*m
== NULL
) return;
630 for (i
= 0; s
[i
] != '\0'; i
++)
633 if ((c
== 10) || (c
== 13))
657 if (escspace
!= 0) spextra
= 1;
660 for (i
= 0; s
[i
] != '\0'; i
++)
668 else if ((c
== 91) || (c
== 93))
670 if (encode
== ASL_ENCODE_ASL
) n
+= 2;
675 n
+= char_encode_len
[c
];
676 if (c
== 32) n
+= spextra
;
689 *m
= reallocf(*m
, n
+ (*x
));
692 if (*m
== NULL
) return;
694 for (i
= 0; s
[i
] != '\0'; i
++)
697 _asl_encode_char(m
, x
, c
, encode
, escspace
);
704 _asl_append_xml_string(char **m
, uint32_t *x
, char *s
)
710 if (m
== NULL
) return;
711 if (x
== NULL
) return;
712 if (s
== NULL
) return;
715 for (i
= 0; s
[i
] != '\0'; i
++)
720 * XML wants & < > " and '
721 * We use &#xnn; for control chars.
722 * Everything else just gets printed "as is" (we know the input is UTF8)
724 if (c
== '&') n
+= 5;
725 else if (c
== '<') n
+= 4;
726 else if (c
== '>') n
+= 4;
727 else if (c
== '"') n
+= 6;
728 else if (c
== '\'') n
+= 6;
729 else if (iscntrl(c
)) n
+= 6;
742 *m
= reallocf(*m
, n
+ (*x
));
745 if (*m
== NULL
) return;
747 for (i
= 0; s
[i
] != '\0'; i
++)
754 memcpy(p
, "&", 5);
762 memcpy(p
, "<", 4);
770 memcpy(p
, ">", 4);
778 memcpy(p
, """, 6);
786 memcpy(p
, "'", 6);
793 snprintf(tmp
, sizeof(tmp
), "&#x%02hhu;", c
);
813 _asl_append_xml_tag(char **m
, uint32_t *x
, int tag
, char *s
)
817 if (m
== NULL
) return;
818 if (x
== NULL
) return;
820 if (tag
== XML_TAG_KEY
)
822 _asl_append_string(m
, x
, "\t\t<key>", ASL_ENCODE_NONE
, 0);
823 _asl_append_xml_string(m
, x
, s
);
824 _asl_append_string(m
, x
, "</key>\n", ASL_ENCODE_NONE
, 0);
828 if (tag
== XML_TAG_STRING
)
830 _asl_append_string(m
, x
, "\t\t<string>", ASL_ENCODE_NONE
, 0);
831 _asl_append_xml_string(m
, x
, s
);
832 _asl_append_string(m
, x
, "</string>\n", ASL_ENCODE_NONE
, 0);
836 if (tag
== XML_TAG_DATA
)
838 _asl_append_string(m
, x
, "\t\t<data>", ASL_ENCODE_NONE
, 0);
839 b64
= (char *)asl_b64_encode((uint8_t *)s
, strlen(s
));
842 _asl_append_string(m
, x
, b64
, ASL_ENCODE_NONE
, 0);
845 _asl_append_string(m
, x
, "</data>\n", ASL_ENCODE_NONE
, 0);
851 _asl_append_op(char **m
, uint32_t *x
, uint32_t op
)
856 if (m
== NULL
) return;
857 if (x
== NULL
) return;
859 if (op
== ASL_QUERY_OP_NULL
) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
862 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
864 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
866 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
868 if (op
& ASL_QUERY_OP_PREFIX
)
870 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
871 else opstr
[i
++] = 'A';
873 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
875 switch (op
& ASL_QUERY_OP_TRUE
)
877 case ASL_QUERY_OP_EQUAL
:
880 case ASL_QUERY_OP_GREATER
:
883 case ASL_QUERY_OP_GREATER_EQUAL
:
887 case ASL_QUERY_OP_LESS
:
890 case ASL_QUERY_OP_LESS_EQUAL
:
894 case ASL_QUERY_OP_NOT_EQUAL
:
897 case ASL_QUERY_OP_TRUE
:
904 if (i
== 0) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
907 return _asl_append_string(m
, x
, opstr
, ASL_ENCODE_NONE
, 0);
911 _asl_time_string(int fmt
, const char *str
)
921 if (str
!= NULL
) tick
= asl_parse_time(str
);
925 asprintf(&out
, "%lu", tick
);
932 asprintf(&out
, "%d.%02d.%02d %02d:%02d:%02d UTC", stm
->tm_year
+ 1900, stm
->tm_mon
+ 1, stm
->tm_mday
, stm
->tm_hour
, stm
->tm_min
, stm
->tm_sec
);
938 ltime
= ctime_r(&tick
, ltbuf
);
939 if (ltime
== NULL
) return NULL
;
941 asprintf(&out
, "%s", ltime
);
949 _asl_msg_to_string_time_fmt(asl_msg_t
*msg
, uint32_t *len
, int tf
)
956 if (msg
== NULL
) return NULL
;
964 if (out
== NULL
) return NULL
;
969 for (i
= 0; i
< msg
->count
; i
++)
971 if (msg
->key
[i
] == NULL
) continue;
972 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
973 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
975 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
977 if ((tf
!= TFMT_SEC
) && (!strcmp(msg
->key
[i
], ASL_KEY_TIME
)))
979 s
= _asl_time_string(tf
, msg
->val
[i
]);
982 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
983 _asl_append_string(&out
, &outlen
, s
, ASL_ENCODE_ASL
, 0);
986 else if (msg
->val
[i
] != NULL
)
988 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
989 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
992 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
995 _asl_append_string(&out
, &outlen
, "\n", ASL_ENCODE_NONE
, 0);
1002 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
1009 if (msg
== NULL
) return NULL
;
1015 if (msg
->type
== ASL_TYPE_QUERY
)
1017 _asl_append_string(&out
, &outlen
, "Q ", ASL_ENCODE_NONE
, 0);
1018 if (out
== NULL
) return NULL
;
1021 if (msg
->count
== 0)
1023 if (out
== NULL
) return NULL
;
1028 for (i
= 0; i
< msg
->count
; i
++)
1030 if (msg
->key
[i
] == NULL
) continue;
1032 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
1033 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
1035 if (msg
->type
== ASL_TYPE_QUERY
)
1037 _asl_append_op(&out
, &outlen
, msg
->op
[i
]);
1038 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
1041 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
1043 if (msg
->val
[i
] != NULL
)
1045 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
1046 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
1049 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
1057 _asl_msg_op_from_string(char *o
)
1061 op
= ASL_QUERY_OP_NULL
;
1063 if (o
== NULL
) return op
;
1065 for (i
= 0; o
[i
] != '\0'; i
++)
1067 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
1068 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
1069 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
1070 if (o
[i
] == 'N') op
|= ASL_QUERY_OP_NUMERIC
;
1071 if (o
[i
] == 'S') op
|= ASL_QUERY_OP_SUBSTRING
;
1072 if (o
[i
] == 'A') op
|= ASL_QUERY_OP_PREFIX
;
1073 if (o
[i
] == 'Z') op
|= ASL_QUERY_OP_SUFFIX
;
1074 if (o
[i
] == '<') op
|= ASL_QUERY_OP_LESS
;
1075 if (o
[i
] == '>') op
|= ASL_QUERY_OP_GREATER
;
1076 if (o
[i
] == '=') op
|= ASL_QUERY_OP_EQUAL
;
1077 if (o
[i
] == '!') op
|= ASL_QUERY_OP_NOT_EQUAL
;
1078 if (o
[i
] == 'T') op
|= ASL_QUERY_OP_TRUE
;
1085 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
1087 char *str
, *out
, c
, oval
;
1088 uint32_t i
, len
, n
, outlen
;
1092 if (p
== NULL
) return NULL
;
1093 if (*p
== NULL
) return NULL
;
1094 if (**p
== '\0') return NULL
;
1096 /* skip one space if it's there (word separator) */
1097 if (**p
== ' ') (*p
)++;
1099 /* skip leading white space */
1102 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
1105 if (**p
== '\0') return NULL
;
1106 if (**p
== '\n') return NULL
;
1117 if (out
== NULL
) return NULL
;
1124 /* scan for token and calulate it's length (input and decoded output len) */
1132 /* stop scanning when we hit a delimiter */
1133 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
1139 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
1144 if (str
[++len
] == '\0') return NULL
;
1148 if (str
[++len
] == '\0') return NULL
;
1149 if (str
[++len
] == '\0') return NULL
;
1151 else if ((c
>= '0') && (c
<= '3'))
1153 if (str
[++len
] == '\0') return NULL
;
1154 if (str
[++len
] == '\0') return NULL
;
1168 if ((len
== 0) && (**p
== ']'))
1173 if (out
== NULL
) return NULL
;
1182 out
= malloc(outlen
+ 1);
1183 if (out
== NULL
) return NULL
;
1186 for (i
= 0; i
< len
; i
++)
1243 if (str
[i
] == '?') out
[n
++] = 127;
1244 else out
[n
++] = str
[i
] - 64;
1253 if (str
[i
] == '?') out
[n
++] = 255;
1254 else out
[n
++] = str
[i
] + 64;
1259 out
[n
++] = str
[i
] + 128;
1269 else if ((c
>= '0') && (c
<= '3'))
1271 oval
= (c
- '0') * 64;
1275 if ((c
< '0') || (c
> '7'))
1282 oval
+= ((c
- '0') * 8);
1286 if ((c
< '0') || (c
> '7'))
1307 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
1318 asl_msg_from_string(const char *buf
)
1320 uint32_t tt
, type
, op
;
1321 char *k
, *v
, *o
, *p
;
1324 if (buf
== NULL
) return NULL
;
1326 type
= ASL_TYPE_MSG
;
1329 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1330 if (k
== NULL
) return NULL
;
1334 type
= ASL_TYPE_QUERY
;
1337 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1339 else if (tt
== TOKEN_INT
)
1341 /* Leading integer is a string length - skip it */
1343 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1344 if (k
== NULL
) return NULL
;
1347 msg
= calloc(1, sizeof(asl_msg_t
));
1348 if (msg
== NULL
) return NULL
;
1352 /* OPEN WORD [WORD [WORD]] CLOSE */
1355 op
= ASL_QUERY_OP_NULL
;
1357 if (tt
!= TOKEN_OPEN
)
1365 /* get op for query type */
1366 if (type
== ASL_TYPE_QUERY
)
1368 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
1369 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
1371 if (o
!= NULL
) free(o
);
1376 op
= _asl_msg_op_from_string(o
);
1380 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1381 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1382 if ((k
== NULL
) || (tt
!= TOKEN_WORD
))
1384 if (k
!= NULL
) free(k
);
1389 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
1390 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1393 asl_set_query(msg
, k
, NULL
, op
);
1397 if (tt
== TOKEN_CLOSE
)
1399 asl_set_query(msg
, k
, NULL
, op
);
1401 else if (tt
== TOKEN_WORD
)
1403 asl_set_query(msg
, k
, v
, op
);
1407 if (k
!= NULL
) free(k
);
1408 if (v
!= NULL
) free(v
);
1413 if (k
!= NULL
) free(k
);
1414 if (v
!= NULL
) free(v
);
1416 if (tt
!= TOKEN_CLOSE
)
1418 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1419 if (k
== NULL
) break;
1421 if (tt
!= TOKEN_CLOSE
)
1430 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1431 if (k
== NULL
) break;
1438 asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
)
1440 uint32_t i
, len
, newlen
;
1443 if (list
== NULL
) return NULL
;
1444 if (list
->count
== 0) return NULL
;
1445 if (list
->msg
== NULL
) return NULL
;
1448 asprintf(&out
, "%u\n", list
->count
);
1449 if (out
== NULL
) return NULL
;
1450 *outlen
= strlen(out
) + 1;
1452 for (i
= 0; i
< list
->count
; i
++)
1455 msgbuf
= asl_msg_to_string(list
->msg
[i
], &len
);
1463 newlen
= *outlen
+ len
;
1464 out
= reallocf(out
, newlen
);
1471 memmove((out
+ *outlen
- 1), msgbuf
, len
);
1472 out
[newlen
- 2] = '\n';
1473 out
[newlen
- 1] = '\0';
1482 asl_search_result_t
*
1483 asl_list_from_string(const char *buf
)
1487 asl_search_result_t
*out
;
1490 if (buf
== NULL
) return NULL
;
1494 if (n
== 0) return NULL
;
1496 out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1497 if (out
== NULL
) return NULL
;
1499 out
->msg
= (asl_msg_t
**)calloc(n
, sizeof(asl_msg_t
*));
1500 if (out
->msg
== NULL
)
1506 for (i
= 0; i
< n
; i
++)
1508 p
= strchr(p
, '\n');
1511 aslresponse_free((aslresponse
)out
);
1517 m
= asl_msg_from_string(p
);
1520 aslresponse_free((aslresponse
)out
);
1532 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1536 if (a
->count
!= b
->count
) return 0;
1538 for (i
= 0; i
< a
->count
; i
++)
1540 j
= _asl_msg_index(b
, a
->key
[i
]);
1541 if (j
== (uint32_t)-1) return 0;
1543 if (a
->val
[i
] == NULL
)
1545 if (b
->val
[j
] != NULL
) return 0;
1549 if (b
->val
[j
] == NULL
) return 0;
1550 if (strcmp(a
->val
[i
], b
->val
[j
])) return 0;
1553 if (a
->type
== ASL_TYPE_QUERY
)
1555 if (a
->op
[i
] != b
->op
[j
]) return 0;
1563 _asl_isanumber(char *s
)
1567 if (s
== NULL
) return 0;
1570 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1572 if (s
[i
] == '\0') return 0;
1574 for (; s
[i
] != '\0'; i
++)
1576 if (!isdigit(s
[i
])) return 0;
1583 _asl_msg_basic_test(uint32_t op
, char *q
, char *m
, uint32_t n
)
1590 t
= op
& ASL_QUERY_OP_TRUE
;
1592 /* NULL value from query or message string fails */
1593 if ((q
== NULL
) || (m
== NULL
)) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1595 if (op
& ASL_QUERY_OP_REGEX
)
1597 /* greater than or less than make no sense in substring search */
1598 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1600 memset(&rex
, 0, sizeof(regex_t
));
1602 rflags
= REG_EXTENDED
| REG_NOSUB
;
1603 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1605 /* A bad reqular expression matches nothing */
1606 if (regcomp(&rex
, q
, rflags
) != 0) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1608 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1611 if (t
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp
!= 0);
1615 if (op
& ASL_QUERY_OP_NUMERIC
)
1617 if (_asl_isanumber(q
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1618 if (_asl_isanumber(m
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1625 case ASL_QUERY_OP_EQUAL
: return (nm
== nq
);
1626 case ASL_QUERY_OP_GREATER
: return (nm
> nq
);
1627 case ASL_QUERY_OP_GREATER_EQUAL
: return (nm
>= nq
);
1628 case ASL_QUERY_OP_LESS
: return (nm
< nq
);
1629 case ASL_QUERY_OP_LESS_EQUAL
: return (nm
<= nq
);
1630 case ASL_QUERY_OP_NOT_EQUAL
: return (nm
!= nq
);
1631 default: return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1636 if (op
& ASL_QUERY_OP_CASEFOLD
)
1638 if (n
== 0) cmp
= strcasecmp(m
, q
);
1639 else cmp
= strncasecmp(m
, q
, n
);
1643 if (n
== 0) cmp
= strcmp(m
, q
);
1644 else cmp
= strncmp(m
, q
, n
);
1649 case ASL_QUERY_OP_EQUAL
: return (cmp
== 0);
1650 case ASL_QUERY_OP_GREATER
: return (cmp
> 0);
1651 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp
>= 0);
1652 case ASL_QUERY_OP_LESS
: return (cmp
< 0);
1653 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp
<= 0);
1654 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp
!= 0);
1657 return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1661 _asl_msg_test_substring(uint32_t op
, char *q
, char *m
)
1663 uint32_t t
, i
, d
, lm
, lq
, match
, newop
;
1665 t
= op
& ASL_QUERY_OP_TRUE
;
1668 if (m
!= NULL
) lm
= strlen(m
);
1671 if (q
!= NULL
) lq
= strlen(q
);
1673 /* NULL is a substring of any string */
1674 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1676 /* A long string is defined to be not equal to a short string */
1677 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1679 /* greater than or less than make no sense in substring search */
1680 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1683 * We scan the string doing an equality test.
1684 * If the input test is equality, we stop as soon as we hit a match.
1685 * Otherwise we keep scanning the whole message string.
1688 newop
|= ASL_QUERY_OP_EQUAL
;
1692 for (i
= 0; i
<= d
; i
++)
1694 if (_asl_msg_basic_test(newop
, q
, m
+ i
, lq
) != 0)
1696 if (t
& ASL_QUERY_OP_EQUAL
) return 1;
1701 /* If the input test was for equality, no matches were found */
1702 if (t
& ASL_QUERY_OP_EQUAL
) return 0;
1704 /* The input test was for not equal. Return true if no matches were found */
1705 return (match
== 0);
1709 _asl_msg_test_prefix(uint32_t op
, char *q
, char *m
)
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 prefix 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 */
1728 return _asl_msg_basic_test(op
, q
, m
, lq
);
1732 _asl_msg_test_suffix(uint32_t op
, char *q
, char *m
)
1734 uint32_t lm
, lq
, d
, t
;
1736 t
= op
& ASL_QUERY_OP_TRUE
;
1739 if (m
!= NULL
) lm
= strlen(m
);
1742 if (q
!= NULL
) lq
= strlen(q
);
1744 /* NULL is a suffix of any string */
1745 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1747 /* A long string is defined to be not equal to a short string */
1748 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1750 /* Compare two equal-length strings */
1752 return _asl_msg_basic_test(op
, q
, m
+ d
, lq
);
1756 * Splits out prefix, suffix, and substring tests.
1757 * Sends the rest to _asl_msg_basic_test().
1760 _asl_msg_test_expression(uint32_t op
, char *q
, char *m
)
1764 t
= op
& ASL_QUERY_OP_TRUE
;
1765 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1767 if (op
& ASL_QUERY_OP_PREFIX
)
1769 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
);
1770 return _asl_msg_test_prefix(op
, q
, m
);
1772 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
);
1774 return _asl_msg_basic_test(op
, q
, m
, 0);
1778 * Special case for comparing time values.
1779 * If both inputs are time strings, this compares the time
1780 * value in seconds. Otherwise it just does normal matching.
1783 _asl_msg_test_time_expression(uint32_t op
, char *q
, char *m
)
1788 if ((op
& ASL_QUERY_OP_PREFIX
) || (op
& ASL_QUERY_OP_SUFFIX
) || (op
& ASL_QUERY_OP_REGEX
)) return _asl_msg_test_expression(op
, q
, m
);
1789 if ((q
== NULL
) || (m
== NULL
)) return _asl_msg_test_expression(op
, q
, m
);
1791 tq
= asl_parse_time(q
);
1792 if (tq
< 0) return _asl_msg_test_expression(op
, q
, m
);
1794 tm
= asl_parse_time(m
);
1795 if (tm
< 0) return _asl_msg_test_expression(op
, q
, m
);
1797 t
= op
& ASL_QUERY_OP_TRUE
;
1801 case ASL_QUERY_OP_FALSE
:
1805 case ASL_QUERY_OP_EQUAL
:
1807 if (tm
== tq
) return 1;
1810 case ASL_QUERY_OP_GREATER
:
1812 if (tm
> tq
) return 1;
1815 case ASL_QUERY_OP_GREATER_EQUAL
:
1817 if (tm
>= tq
) return 1;
1820 case ASL_QUERY_OP_LESS
:
1822 if (tm
< tq
) return 1;
1825 case ASL_QUERY_OP_LESS_EQUAL
:
1827 if (tm
<= tq
) return 1;
1830 case ASL_QUERY_OP_NOT_EQUAL
:
1832 if (tm
!= tq
) return 1;
1835 case ASL_QUERY_OP_TRUE
:
1845 /* test a query against a message */
1847 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
1853 * Check each simple expression (key op val) separately.
1854 * The query suceeds (returns 1) if all simple expressions
1855 * succeed (i.e. AND the simple expressions).
1857 for (i
= 0; i
< q
->count
; i
++)
1859 /* Find query key[i] in the message */
1860 j
= _asl_msg_index(m
, q
->key
[i
]);
1862 /* NULL op is meaningless, but we allow it to succeed */
1863 if (q
->op
== NULL
) continue;
1865 /* ASL_QUERY_OP_TRUE tests if key[i] is present in the message */
1866 t
= q
->op
[i
] & ASL_QUERY_OP_TRUE
;
1867 if (t
== ASL_QUERY_OP_TRUE
)
1869 if (j
== (uint32_t)-1) return 0;
1873 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1874 if (t
== ASL_QUERY_OP_FALSE
)
1876 if (j
!= (uint32_t)-1) return 0;
1880 if (j
== (uint32_t)-1)
1882 /* the message does NOT have query key[i] - fail unless we are testing not equal */
1883 if (t
== ASL_QUERY_OP_NOT_EQUAL
) continue;
1888 if (streq(q
->key
[i
], ASL_KEY_TIME
))
1890 cmp
= _asl_msg_test_time_expression(q
->op
[i
], q
->val
[i
], m
->val
[j
]);
1894 cmp
= _asl_msg_test_expression(q
->op
[i
], q
->val
[i
], m
->val
[j
]);
1897 if (cmp
== 0) return 0;
1904 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1906 if (a
== NULL
) return 0;
1907 if (b
== NULL
) return 0;
1909 if (a
->type
== b
->type
) return _asl_msg_equal(a
, b
);
1910 if (a
->type
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
);
1911 return _asl_msg_test(b
, a
);
1915 * asl_add_file: write log messages to the given file descriptor
1916 * Log messages will be written to this file as well as to the server.
1919 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
1922 int use_global_lock
;
1925 use_global_lock
= 0;
1926 asl
= (asl_client_t
*)ac
;
1929 asl
= _asl_open_default();
1930 if (asl
== NULL
) return -1;
1931 pthread_mutex_lock(&_asl_global
.lock
);
1932 use_global_lock
= 1;
1935 for (i
= 0; i
< asl
->fd_count
; i
++)
1937 if (asl
->fd_list
[i
] == fd
)
1939 /* update message format, time format, and text encoding */
1940 if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
1941 asl
->fd_mfmt
[i
] = NULL
;
1942 if (mfmt
!= NULL
) asl
->fd_mfmt
[i
] = strdup(mfmt
);
1944 if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
1945 asl
->fd_tfmt
[i
] = NULL
;
1946 if (tfmt
!= NULL
) asl
->fd_tfmt
[i
] = strdup(tfmt
);
1948 asl
->fd_encoding
[i
] = text_encoding
;
1950 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1955 if (asl
->fd_count
== 0)
1957 asl
->fd_list
= (int *)calloc(1, sizeof(int));
1958 asl
->fd_mfmt
= (char **)calloc(1, sizeof(char *));
1959 asl
->fd_tfmt
= (char **)calloc(1, sizeof(char *));
1960 asl
->fd_encoding
= (uint32_t *)calloc(1, sizeof(int));
1964 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, (1 + asl
->fd_count
) * sizeof(int));
1965 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, (1 + asl
->fd_count
) * sizeof(char *));
1966 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, (1 + asl
->fd_count
) * sizeof(char *));
1967 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, (1 + asl
->fd_count
) * sizeof(uint32_t));
1970 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
1972 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
1973 if (asl
->fd_mfmt
!= NULL
) free(asl
->fd_mfmt
);
1974 if (asl
->fd_tfmt
!= NULL
) free(asl
->fd_tfmt
);
1975 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
1977 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1981 asl
->fd_list
[asl
->fd_count
] = fd
;
1982 if (mfmt
!= NULL
) asl
->fd_mfmt
[asl
->fd_count
] = strdup(mfmt
);
1983 if (tfmt
!= NULL
) asl
->fd_tfmt
[asl
->fd_count
] = strdup(tfmt
);
1984 asl
->fd_encoding
[asl
->fd_count
] = text_encoding
;
1988 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1993 asl_add_log_file(aslclient ac
, int fd
)
1995 return asl_add_output(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
1999 * asl_remove_output: stop writing log messages to the given file descriptor
2002 asl_remove_output(aslclient ac
, int fd
)
2005 int x
, use_global_lock
;
2008 use_global_lock
= 0;
2009 asl
= (asl_client_t
*)ac
;
2012 asl
= _asl_open_default();
2013 if (asl
== NULL
) return -1;
2014 pthread_mutex_lock(&_asl_global
.lock
);
2015 use_global_lock
= 1;
2018 if (asl
->fd_count
== 0)
2020 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2025 for (i
= 0; i
< asl
->fd_count
; i
++)
2027 if (asl
->fd_list
[i
] == fd
)
2036 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2040 if (asl
->fd_mfmt
[x
] != NULL
) free(asl
->fd_mfmt
[x
]);
2041 if (asl
->fd_tfmt
[x
] != NULL
) free(asl
->fd_tfmt
[x
]);
2043 for (i
= x
+ 1; i
< asl
->fd_count
; i
++, x
++)
2045 asl
->fd_list
[x
] = asl
->fd_list
[i
];
2046 asl
->fd_mfmt
[x
] = asl
->fd_mfmt
[i
];
2047 asl
->fd_tfmt
[x
] = asl
->fd_tfmt
[i
];
2048 asl
->fd_encoding
[x
] = asl
->fd_encoding
[i
];
2053 if (asl
->fd_count
== 0)
2056 asl
->fd_list
= NULL
;
2059 asl
->fd_mfmt
= NULL
;
2062 asl
->fd_tfmt
= NULL
;
2064 free(asl
->fd_encoding
);
2065 asl
->fd_encoding
= NULL
;
2069 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, asl
->fd_count
* sizeof(int));
2070 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, asl
->fd_count
* sizeof(char *));
2071 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, asl
->fd_count
* sizeof(char *));
2072 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, asl
->fd_count
* sizeof(uint32_t));
2074 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
2076 if (asl
->fd_list
!= NULL
)
2079 asl
->fd_list
= NULL
;
2082 if (asl
->fd_mfmt
!= NULL
)
2084 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
2086 asl
->fd_mfmt
= NULL
;
2089 if (asl
->fd_tfmt
!= NULL
)
2091 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
2093 asl
->fd_tfmt
= NULL
;
2096 if (asl
->fd_encoding
!= NULL
)
2098 free(asl
->fd_encoding
);
2099 asl
->fd_encoding
= NULL
;
2103 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2108 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2113 asl_remove_log_file(aslclient ac
, int fd
)
2115 return asl_remove_output(ac
, fd
);
2119 asl_set_filter(aslclient ac
, int f
)
2121 int last
, use_global_lock
;
2124 use_global_lock
= 0;
2125 asl
= (asl_client_t
*)ac
;
2128 asl
= _asl_open_default();
2129 if (asl
== NULL
) return -1;
2130 pthread_mutex_lock(&_asl_global
.lock
);
2131 use_global_lock
= 1;
2137 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2142 * asl_key: examine attribute keys
2143 * returns the key of the nth attribute in a message (beginning at zero)
2144 * returns NULL if the message has fewer attributes
2147 asl_key(aslmsg a
, uint32_t n
)
2151 msg
= (asl_msg_t
*)a
;
2152 if (msg
== NULL
) return NULL
;
2154 if (n
>= msg
->count
) return NULL
;
2159 * asl_new: create a new log message.
2162 asl_new(uint32_t type
)
2167 msg
= calloc(1, sizeof(asl_msg_t
));
2168 if (msg
== NULL
) return NULL
;
2171 if (type
== ASL_TYPE_QUERY
) return (aslmsg
)msg
;
2174 * Defaut attributes are:
2186 msg
->key
= calloc(msg
->count
, sizeof(char *));
2187 if (msg
->key
== NULL
)
2193 msg
->val
= calloc(msg
->count
, sizeof(char *));
2194 if (msg
->val
== NULL
)
2202 msg
->key
[i
] = strdup(ASL_KEY_TIME
);
2203 if (msg
->key
[i
] == NULL
)
2210 msg
->key
[i
] = strdup(ASL_KEY_HOST
);
2211 if (msg
->key
[i
] == NULL
)
2218 msg
->key
[i
] = strdup(ASL_KEY_SENDER
);
2219 if (msg
->key
[i
] == NULL
)
2226 msg
->key
[i
] = strdup(ASL_KEY_PID
);
2227 if (msg
->key
[i
] == NULL
)
2234 msg
->key
[i
] = strdup(ASL_KEY_UID
);
2235 if (msg
->key
[i
] == NULL
)
2242 msg
->key
[i
] = strdup(ASL_KEY_GID
);
2243 if (msg
->key
[i
] == NULL
)
2250 msg
->key
[i
] = strdup(ASL_KEY_LEVEL
);
2251 if (msg
->key
[i
] == NULL
)
2258 msg
->key
[i
] = strdup(ASL_KEY_MSG
);
2259 if (msg
->key
[i
] == NULL
)
2269 * asl_get: get attribute values from a message
2271 * key: attribute key
2272 * returns the attribute value
2273 * returns NULL if the message does not contain the key
2276 asl_get(aslmsg a
, const char *key
)
2281 msg
= (asl_msg_t
*)a
;
2283 if (msg
== NULL
) return NULL
;
2285 i
= _asl_msg_index(msg
, key
);
2286 if (i
== (uint32_t)-1) return NULL
;
2290 #endif /* BUILDING_VARIANT */
2293 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
2296 * level: the log level of the associated message
2297 * format: A formating string followed by a list of arguments, like vprintf()
2298 * returns 0 for success, non-zero for failure
2301 asl_vlog(aslclient ac
, aslmsg a
, int level
, const char *format
, va_list ap
)
2303 int status
, saved_errno
;
2305 char *str
, *fmt
, *estr
;
2306 uint32_t i
, len
, elen
, expand
, my_msg
;
2309 asl
= (asl_client_t
*)ac
;
2313 * Initialize _asl_global so that asl_new will have global data.
2314 * Not strictly necessary, but helps performance.
2316 asl
= _asl_open_default();
2317 if (asl
== NULL
) return -1;
2320 saved_errno
= errno
;
2322 if (format
== NULL
) return -1;
2324 msg
= (asl_msg_t
*)a
;
2330 msg
= asl_new(ASL_TYPE_MSG
);
2331 if (msg
== NULL
) return -1;
2334 if (msg
->type
!= ASL_TYPE_MSG
) return -1;
2336 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
2337 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
2339 /* insert strerror for %m */
2342 estr
= strdup(strerror(saved_errno
));
2345 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2353 elen
= strlen(estr
);
2355 for (i
= 0; format
[i
] != '\0'; i
++)
2357 if (format
[i
] == '%')
2359 if (format
[i
+1] == '\0') len
++;
2360 else if (format
[i
+1] == 'm')
2376 fmt
= (char *)format
;
2380 fmt
= malloc(len
+ 1);
2383 if (estr
!= NULL
) free(estr
);
2389 for (i
= 0; format
[i
] != '\0'; i
++)
2391 if (format
[i
] == '%')
2393 if (format
[i
+1] == '\0')
2396 else if (format
[i
+1] == 'm')
2398 memcpy(fmt
+len
, estr
, elen
);
2404 fmt
[len
++] = format
[i
++];
2405 fmt
[len
++] = format
[i
];
2408 else fmt
[len
++] = format
[i
];
2414 if (estr
!= NULL
) free(estr
);
2416 vasprintf(&str
, fmt
, ap
);
2417 if (expand
!= 0) free(fmt
);
2421 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2425 status
= _asl_send_level_message(ac
, (aslmsg
)msg
, level
, str
);
2428 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2433 * asl_log: log a message with a particular log level
2435 * level: the log level
2436 * format: A formating string followed by a list of arguments, like printf()
2437 * returns 0 for success, non-zero for failure
2440 asl_log(aslclient ac
, aslmsg a
, int level
, const char *format
, ...)
2445 if (format
== NULL
) return -1;
2447 va_start(ap
, format
);
2448 status
= asl_vlog(ac
, a
, level
, format
, ap
);
2454 #ifndef BUILDING_VARIANT
2457 _asl_level_string(int level
)
2459 if (level
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
;
2460 if (level
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
;
2461 if (level
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
;
2462 if (level
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
;
2463 if (level
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
;
2464 if (level
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
;
2465 if (level
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
;
2466 if (level
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
;
2471 * format a message for printing
2472 * out parameter len returns string length including trailing NUL
2475 asl_format_message(aslmsg msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
2477 char *out
, *tstr
, *k
, c
[2];
2478 const char *hstr
, *sstr
, *pstr
, *mstr
, *lstr
, *rprc
, *rpid
, *v
;
2479 int i
, j
, l
, mf
, tf
, paren
, oval
, level
;
2484 if (msg
== NULL
) return NULL
;
2489 if (mfmt
== NULL
) mf
= MFMT_RAW
;
2490 else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf
= MFMT_RAW
;
2491 else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf
= MFMT_STD
;
2492 else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf
= MFMT_BSD
;
2493 else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf
= MFMT_XML
;
2494 else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf
= MFMT_MSG
;
2497 if (tfmt
== NULL
) tf
= TFMT_SEC
;
2498 else if (!strcmp(tfmt
, ASL_TIME_FMT_SEC
)) tf
= TFMT_SEC
;
2499 else if (!strcmp(tfmt
, ASL_TIME_FMT_UTC
)) tf
= TFMT_UTC
;
2500 else if (!strcmp(tfmt
, ASL_TIME_FMT_LCL
)) tf
= TFMT_LCL
;
2504 out
= _asl_msg_to_string_time_fmt((asl_msg_t
*)msg
, len
, tf
);
2510 mstr
= asl_get(msg
, ASL_KEY_MSG
);
2511 if (mstr
== NULL
) return NULL
;
2513 _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2514 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2519 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
2521 /* BSD: Mth dd hh:mm:ss host sender[pid]: message */
2522 /* BSD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]): message */
2523 /* STD: Mth dd hh:mm:ss host sender[pid] <Level>: message */
2524 /* STD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]) <Level>: message */
2526 v
= asl_get(msg
, ASL_KEY_TIME
);
2527 tstr
= _asl_time_string(tf
, v
);
2529 hstr
= asl_get(msg
, ASL_KEY_HOST
);
2530 sstr
= asl_get(msg
, ASL_KEY_SENDER
);
2531 pstr
= asl_get(msg
, ASL_KEY_PID
);
2532 mstr
= asl_get(msg
, ASL_KEY_MSG
);
2534 rprc
= asl_get(msg
, ASL_KEY_REF_PROC
);
2535 rpid
= asl_get(msg
, ASL_KEY_REF_PID
);
2541 lstr
= asl_get(msg
, ASL_KEY_LEVEL
);
2542 if (lstr
!= NULL
) level
= atoi(lstr
);
2547 _asl_append_string(&out
, len
, "0", ASL_ENCODE_NONE
, 0);
2551 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2555 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2557 if (hstr
== NULL
) _asl_append_string(&out
, len
, "unknown", ASL_ENCODE_NONE
, 0);
2558 else _asl_append_string(&out
, len
, hstr
, text_encoding
, 0);
2560 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2562 if (sstr
== NULL
) _asl_append_string(&out
, len
, "unknown", ASL_ENCODE_NONE
, 0);
2563 else _asl_append_string(&out
, len
, sstr
, text_encoding
, 0);
2565 if ((pstr
!= NULL
) && (strcmp(pstr
, "-1")))
2567 _asl_append_string(&out
, len
, "[", ASL_ENCODE_NONE
, 0);
2568 _asl_append_string(&out
, len
, pstr
, ASL_ENCODE_NONE
, 0);
2569 _asl_append_string(&out
, len
, "]", ASL_ENCODE_NONE
, 0);
2572 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, " (", ASL_ENCODE_NONE
, 0);
2574 if (rprc
!= NULL
) _asl_append_string(&out
, len
, rprc
, text_encoding
, 0);
2577 _asl_append_string(&out
, len
, "[", ASL_ENCODE_NONE
, 0);
2578 _asl_append_string(&out
, len
, rpid
, ASL_ENCODE_NONE
, 0);
2579 _asl_append_string(&out
, len
, "]", ASL_ENCODE_NONE
, 0);
2582 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, ")", ASL_ENCODE_NONE
, 0);
2586 _asl_append_string(&out
, len
, " <", ASL_ENCODE_NONE
, 0);
2587 _asl_append_string(&out
, len
, _asl_level_string(level
), ASL_ENCODE_NONE
, 0);
2588 _asl_append_string(&out
, len
, ">", ASL_ENCODE_NONE
, 0);
2591 _asl_append_string(&out
, len
, ": ", ASL_ENCODE_NONE
, 0);
2593 if (mstr
!= NULL
) _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2595 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2601 _asl_append_string(&out
, len
, "\t<dict>\n", ASL_ENCODE_NONE
, 0);
2603 for (i
= 0; i
< msg
->count
; i
++)
2605 if (asl_is_utf8(msg
->key
[i
]) == 1)
2607 _asl_append_xml_tag(&out
, len
, XML_TAG_KEY
, msg
->key
[i
]);
2608 if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
2610 tstr
= _asl_time_string(tf
, msg
->val
[i
]);
2611 _asl_append_xml_tag(&out
, len
, XML_TAG_STRING
, tstr
);
2612 if (tstr
!= NULL
) free(tstr
);
2616 if (asl_is_utf8(msg
->val
[i
]) == 1) _asl_append_xml_tag(&out
, len
, XML_TAG_STRING
, msg
->val
[i
]);
2617 else _asl_append_xml_tag(&out
, len
, XML_TAG_DATA
, msg
->val
[i
]);
2622 _asl_append_string(&out
, len
, "\t</dict>\n", ASL_ENCODE_NONE
, 0);
2629 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2645 if (out
!= NULL
) free(out
);
2651 for (j
= i
; mfmt
[j
] != '\0'; j
++)
2654 if (mfmt
[j
] == '\\') c
[0] = mfmt
[++j
];
2655 else if ((paren
== 1) && (mfmt
[j
] ==')')) break;
2656 else if (mfmt
[j
] != ' ') c
[0] = mfmt
[j
];
2658 if (c
[0] == '\0') break;
2660 k
= reallocf(k
, l
+ 1);
2663 if (out
!= NULL
) free(out
);
2672 if (paren
== 1) j
++;
2676 v
= asl_get(msg
, k
);
2679 if (!strcmp(k
, ASL_KEY_TIME
))
2681 tstr
= _asl_time_string(tf
, v
);
2682 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2683 if (tstr
!= NULL
) free(tstr
);
2687 _asl_append_string(&out
, len
, (char *)v
, ASL_ENCODE_NONE
, 0);
2694 if (mfmt
[i
] == '\\')
2697 if (mfmt
[i
] == '$') _asl_append_string(&out
, len
, "$", ASL_ENCODE_NONE
, 0);
2698 else if (mfmt
[i
] == 'e') _asl_append_string(&out
, len
, "\e", ASL_ENCODE_NONE
, 0);
2699 else if (mfmt
[i
] == 's') _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2700 else if (mfmt
[i
] == 'a') _asl_append_string(&out
, len
, "\a", ASL_ENCODE_NONE
, 0);
2701 else if (mfmt
[i
] == 'b') _asl_append_string(&out
, len
, "\b", ASL_ENCODE_NONE
, 0);
2702 else if (mfmt
[i
] == 'f') _asl_append_string(&out
, len
, "\f", ASL_ENCODE_NONE
, 0);
2703 else if (mfmt
[i
] == 'n') _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2704 else if (mfmt
[i
] == 'r') _asl_append_string(&out
, len
, "\r", ASL_ENCODE_NONE
, 0);
2705 else if (mfmt
[i
] == 't') _asl_append_string(&out
, len
, "\t", ASL_ENCODE_NONE
, 0);
2706 else if (mfmt
[i
] == 'v') _asl_append_string(&out
, len
, "\v", ASL_ENCODE_NONE
, 0);
2707 else if (mfmt
[i
] == '\'') _asl_append_string(&out
, len
, "\'", ASL_ENCODE_NONE
, 0);
2708 else if (mfmt
[i
] == '\\') _asl_append_string(&out
, len
, "\\", ASL_ENCODE_NONE
, 0);
2709 else if (isdigit(mfmt
[i
]))
2711 oval
= mfmt
[i
] - '0';
2712 if (isdigit(mfmt
[i
+1]))
2715 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2716 if (isdigit(mfmt
[i
+1]))
2719 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2723 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2728 if (mfmt
[i
] == '\0') break;
2730 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2733 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2739 * asl_send (internal version): send a message
2740 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
2741 * has been used to set all of a message's attributes.
2742 * returns 0 for success, non-zero for failure
2744 __private_extern__
int
2745 _asl_send_level_message(aslclient ac
, aslmsg msg
, int level
, const char *message
)
2747 char *str
, *out_raw
;
2749 uint32_t i
, len
, outlen
, lmask
, outstatus
, filter
, check
, senderx
, facilityx
;
2754 struct timeval tval
;
2755 int status
, rc_filter
;
2757 int use_global_lock
;
2758 asl_msg_t
*mt
, *tmp_msg
;
2759 char hname
[_POSIX_HOST_NAME_MAX
];
2760 kern_return_t kstatus
;
2762 use_global_lock
= 0;
2763 asl
= (asl_client_t
*)ac
;
2766 asl
= _asl_open_default();
2767 if (asl
== NULL
) return -1;
2768 use_global_lock
= 1;
2771 if (msg
== NULL
) return 0;
2773 val
= asl_get(msg
, ASL_KEY_LEVEL
);
2774 if (val
!= NULL
) level
= atoi(val
);
2776 lmask
= ASL_FILTER_MASK(level
);
2778 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
2780 pthread_mutex_lock(&_asl_global
.lock
);
2782 if (_asl_global
.rc_change_token
>= 0)
2784 /* initialize or re-check process-specific and master filters */
2786 status
= notify_check(_asl_global
.rc_change_token
, &check
);
2787 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
2789 if (_asl_global
.master_token
>= 0)
2792 status
= notify_get_state(_asl_global
.master_token
, &v64
);
2793 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
2796 if (_asl_global
.notify_token
>= 0)
2799 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
2800 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
2805 pthread_mutex_unlock(&_asl_global
.lock
);
2808 filter
= asl
->filter
;
2811 /* master filter overrides local filter */
2812 if (_asl_global
.master_filter
!= 0)
2814 filter
= _asl_global
.master_filter
;
2818 /* process-specific filter overrides local and master */
2819 if (_asl_global
.proc_filter
!= 0)
2821 filter
= _asl_global
.proc_filter
;
2826 * Copy the message to tmp_msg to make setting values thread-safe
2828 tmp_msg
= calloc(1, sizeof(asl_msg_t
));
2829 if (tmp_msg
== NULL
) return -1;
2831 tmp_msg
->type
= ASL_TYPE_MSG
;
2833 mt
= (asl_msg_t
*)msg
;
2834 for (i
= 0; i
< mt
->count
; i
++)
2836 asl_set(tmp_msg
, mt
->key
[i
], mt
->val
[i
]);
2840 * Set Level and Message from parameters.
2842 if (message
!= NULL
) asl_set(tmp_msg
, ASL_KEY_MSG
, message
);
2843 asl_set(tmp_msg
, ASL_KEY_LEVEL
, _asl_level_string(level
));
2846 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here
2849 memset(&tval
, 0, sizeof(struct timeval
));
2851 status
= gettimeofday(&tval
, NULL
);
2854 asprintf(&str
, "%lu", tval
.tv_sec
);
2857 asl_set(tmp_msg
, ASL_KEY_TIME
, str
);
2862 asprintf(&str
, "%lu", tval
.tv_usec
* 1000);
2865 asl_set(tmp_msg
, ASL_KEY_TIME_NSEC
, str
);
2873 asprintf(&str
, "%lu", tick
);
2876 asl_set(tmp_msg
, ASL_KEY_TIME
, str
);
2882 memset(&hname
, 0, _POSIX_HOST_NAME_MAX
);
2883 if (gethostname(hname
, _POSIX_HOST_NAME_MAX
) == 0)
2885 asl_set(tmp_msg
, ASL_KEY_HOST
, hname
);
2889 asprintf(&str
, "%u", getpid());
2892 asl_set(tmp_msg
, ASL_KEY_PID
, str
);
2897 asprintf(&str
, "%d", getuid());
2900 asl_set(tmp_msg
, ASL_KEY_UID
, str
);
2905 asprintf(&str
, "%u", getgid());
2908 asl_set(tmp_msg
, ASL_KEY_GID
, str
);
2912 senderx
= (uint32_t)-1;
2913 facilityx
= (uint32_t)-1;
2915 for (i
= 0; (i
< tmp_msg
->count
) && ((senderx
== (uint32_t)-1) || (facilityx
== (uint32_t)-1)); i
++)
2917 if (tmp_msg
->key
[i
] == NULL
) continue;
2918 if (streq(tmp_msg
->key
[i
], ASL_KEY_SENDER
)) senderx
= i
;
2919 else if (streq(tmp_msg
->key
[i
], ASL_KEY_FACILITY
)) facilityx
= i
;
2923 * Set Sender if needed
2925 if ((senderx
== (uint32_t)-1) || (tmp_msg
->val
[senderx
] == NULL
))
2927 if ((ac
!= NULL
) && (ac
->name
!= NULL
))
2929 /* Use the Sender name from the client handle */
2930 asl_set(tmp_msg
, ASL_KEY_SENDER
, ac
->name
);
2934 /* Get the value for ASL_KEY_SENDER from cache */
2935 if (_asl_global
.sender
== NULL
)
2937 name
= *(*_NSGetArgv());
2940 x
= strrchr(name
, '/');
2944 pthread_mutex_lock(&_asl_global
.lock
);
2946 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
2947 pthread_mutex_unlock(&_asl_global
.lock
);
2951 if (_asl_global
.sender
!= NULL
) asl_set(tmp_msg
, ASL_KEY_SENDER
, _asl_global
.sender
);
2952 else asl_set(tmp_msg
, ASL_KEY_SENDER
, "Unknown");
2959 if ((facilityx
== (uint32_t)-1) || (tmp_msg
->val
[facilityx
] == NULL
))
2961 if ((ac
!= NULL
) && (ac
->facility
!= NULL
))
2963 /* Use the Facility name from the client handle */
2964 asl_set(tmp_msg
, ASL_KEY_FACILITY
, ac
->facility
);
2968 /* Set "ASLOption store" if remote control is active */
2971 val
= asl_get(msg
, ASL_KEY_OPTION
);
2974 asl_set(tmp_msg
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
2979 asprintf(&str
, "%s %s", ASL_OPT_STORE
, val
);
2982 asl_set(tmp_msg
, ASL_KEY_OPTION
, str
);
2991 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
2993 if ((filter
!= 0) && ((filter
& lmask
) != 0))
2996 out_raw
= asl_msg_to_string(tmp_msg
, &len
);
2998 if ((out_raw
!= NULL
) && (len
!= 0))
3000 /* send a mach message to syslogd */
3002 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&out
, outlen
+ 1, TRUE
);
3003 if (kstatus
== KERN_SUCCESS
)
3005 memset(out
, 0, outlen
+ 1);
3006 snprintf((char *)out
, outlen
, "%10u %s", len
, out_raw
);
3010 pthread_mutex_lock(&(_asl_global
.port_lock
));
3012 if (_asl_global
.server_port
== MACH_PORT_NULL
)
3014 _asl_global
.port_count
= 0;
3016 kstatus
= bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &_asl_global
.server_port
);
3017 if (kstatus
== KERN_SUCCESS
) _asl_global
.port_count
= 1;
3018 else _asl_global
.server_port
= MACH_PORT_NULL
;
3021 pthread_mutex_unlock(&(_asl_global
.port_lock
));
3023 if (kstatus
== KERN_SUCCESS
) kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)out
, outlen
+ 1);
3024 else vm_deallocate(mach_task_self(), (vm_address_t
)out
, outlen
+ 1);
3026 if (kstatus
== KERN_SUCCESS
) outstatus
= 0;
3035 /* write to file descriptors */
3036 for (i
= 0; i
< asl
->fd_count
; i
++)
3038 if (asl
->fd_list
[i
] < 0) continue;
3041 out
= asl_format_message(tmp_msg
, asl
->fd_mfmt
[i
], asl
->fd_tfmt
[i
], asl
->fd_encoding
[i
], &len
);
3042 if (out
== NULL
) continue;
3044 status
= write(asl
->fd_list
[i
], out
, len
- 1);
3047 asl
->fd_list
[i
] = -1;
3054 asl_free((aslmsg
)tmp_msg
);
3056 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
3062 * asl_send: send a message
3063 * returns 0 for success, non-zero for failure
3066 asl_send(aslclient ac
, aslmsg msg
)
3068 return _asl_send_level_message(ac
, msg
, ASL_LEVEL_DEBUG
, NULL
);
3072 asl_msg_string(aslmsg a
)
3076 return asl_msg_to_string((asl_msg_t
*)a
, &len
);
3080 * asl_free: free a message
3081 * msg: an aslmsg to free
3089 msg
= (asl_msg_t
*)a
;
3091 if (msg
== NULL
) return;
3093 for (i
= 0; i
< msg
->count
; i
++)
3095 if (msg
->key
[i
] != NULL
) free(msg
->key
[i
]);
3096 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3101 if (msg
->key
!= NULL
) free(msg
->key
);
3102 if (msg
->val
!= NULL
) free(msg
->val
);
3103 if (msg
->op
!= NULL
) free(msg
->op
);
3110 * Called if there's a malloc error while manipulating a message in asl_set_query.
3111 * Cleans up the key, val, and op fields, sets count to zero.
3114 _asl_clear_msg(asl_msg_t
*msg
)
3118 if (msg
== NULL
) return;
3120 for (i
= 0; i
< msg
->count
; i
++)
3122 if (msg
->key
!= NULL
&& msg
->key
[i
] != NULL
) free(msg
->key
[i
]);
3123 if (msg
->val
!= NULL
&& msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3126 if (msg
->key
!= NULL
) free(msg
->key
);
3127 if (msg
->val
!= NULL
) free(msg
->val
);
3128 if (msg
->op
!= NULL
) free(msg
->op
);
3138 * asl_set_query: set arbitrary parameters of a query
3139 * Similar to als_set, but allows richer query operations.
3140 * See ASL_QUERY_OP_* above.
3142 * key: attribute key
3143 * value: attribute value
3144 * op: an operation from the set above.
3145 * returns 0 for success, non-zero for failure
3148 asl_set_query(aslmsg a
, const char *key
, const char *val
, uint32_t op
)
3154 msg
= (asl_msg_t
*)a
;
3156 if (msg
== NULL
) return 0;
3157 if (key
== NULL
) return -1;
3161 if ((streq(key
, ASL_KEY_MSG
)) && (val
!= NULL
))
3163 /* strip trailing newlines */
3165 if (dv
== NULL
) return -1;
3169 while ((len
> 0) && (dv
[i
] == '\n'))
3176 else if (streq(key
, ASL_KEY_LEVEL
))
3178 if (val
== NULL
) return -1;
3179 if (val
[0] == '\0') return -1;
3180 if ((val
[0] >= '0') && (val
[0] <= '9'))
3183 asprintf(&dv
, "%d", i
);
3184 if (dv
== NULL
) return -1;
3186 else if (!strcasecmp(val
, ASL_STRING_EMERG
))
3189 if (dv
== NULL
) return -1;
3191 else if (!strcasecmp(val
, ASL_STRING_ALERT
))
3194 if (dv
== NULL
) return -1;
3196 else if (!strcasecmp(val
, ASL_STRING_CRIT
))
3199 if (dv
== NULL
) return -1;
3201 else if (!strcasecmp(val
, ASL_STRING_ERR
))
3204 if (dv
== NULL
) return -1;
3206 else if (!strcasecmp(val
, ASL_STRING_WARNING
))
3209 if (dv
== NULL
) return -1;
3211 else if (!strcasecmp(val
, ASL_STRING_NOTICE
))
3214 if (dv
== NULL
) return -1;
3216 else if (!strcasecmp(val
, ASL_STRING_INFO
))
3219 if (dv
== NULL
) return -1;
3221 else if (!strcasecmp(val
, ASL_STRING_DEBUG
))
3224 if (dv
== NULL
) return -1;
3229 if ((dv
== NULL
) && (val
!= NULL
))
3232 if (dv
== NULL
) return -1;
3235 for (i
= 0; i
< msg
->count
; i
++)
3237 if (msg
->key
[i
] == NULL
) continue;
3239 if ((msg
->type
!= ASL_TYPE_QUERY
) && (streq(msg
->key
[i
], key
)))
3241 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3243 if (val
!= NULL
) msg
->val
[i
] = dv
;
3244 if (msg
->op
!= NULL
) msg
->op
[i
] = op
;
3249 if (msg
->count
== 0)
3251 msg
->key
= (char **)calloc(1, sizeof(char *));
3252 if (msg
->key
== NULL
)
3254 _asl_clear_msg(msg
);
3258 msg
->val
= (char **)calloc(1, sizeof(char *));
3259 if (msg
->val
== NULL
)
3261 _asl_clear_msg(msg
);
3265 if (msg
->type
== ASL_TYPE_QUERY
)
3267 msg
->op
= (uint32_t *)calloc(1, sizeof(uint32_t));
3268 if (msg
->op
== NULL
)
3270 _asl_clear_msg(msg
);
3277 msg
->key
= (char **)reallocf(msg
->key
, (msg
->count
+ 1) * sizeof(char *));
3278 if (msg
->key
== NULL
)
3280 _asl_clear_msg(msg
);
3284 msg
->val
= (char **)reallocf(msg
->val
, (msg
->count
+ 1) * sizeof(char *));
3285 if (msg
->val
== NULL
)
3287 _asl_clear_msg(msg
);
3291 if (msg
->type
== ASL_TYPE_QUERY
)
3293 msg
->op
= (uint32_t *)reallocf(msg
->op
, (msg
->count
+ 1) * sizeof(uint32_t));
3294 if (msg
->op
== NULL
)
3296 _asl_clear_msg(msg
);
3305 if (dv
!= NULL
) free(dv
);
3306 _asl_clear_msg(msg
);
3310 msg
->key
[msg
->count
] = dk
;
3311 msg
->val
[msg
->count
] = dv
;
3312 if (msg
->op
!= NULL
) msg
->op
[msg
->count
] = op
;
3319 * asl_set: set attributes of a message
3321 * key: attribute key
3322 * value: attribute value
3323 * returns 0 for success, non-zero for failure
3326 asl_set(aslmsg msg
, const char *key
, const char *val
)
3328 return asl_set_query(msg
, key
, val
, 0);
3332 * asl_unset: remove attributes of a message
3334 * key: attribute key
3335 * returns 0 for success, non-zero for failure
3338 asl_unset(aslmsg a
, const char *key
)
3343 msg
= (asl_msg_t
*)a
;
3345 if (msg
== NULL
) return 0;
3346 if (key
== NULL
) return 0;
3348 for (i
= 0; i
< msg
->count
; i
++)
3350 if (msg
->key
[i
] == NULL
) continue;
3352 if (streq(msg
->key
[i
], key
))
3355 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3357 for (j
= i
+ 1; j
< msg
->count
; j
++, i
++)
3359 msg
->key
[i
] = msg
->key
[j
];
3360 msg
->val
[i
] = msg
->val
[j
];
3361 if (msg
->op
!= NULL
) msg
->op
[i
] = msg
->op
[j
];
3366 if (msg
->count
== 0)
3374 if (msg
->op
!= NULL
) free(msg
->op
);
3379 msg
->key
= (char **)reallocf(msg
->key
, msg
->count
* sizeof(char *));
3380 if (msg
->key
== NULL
) return -1;
3382 msg
->val
= (char **)reallocf(msg
->val
, msg
->count
* sizeof(char *));
3383 if (msg
->val
== NULL
) return -1;
3385 if (msg
->op
!= NULL
)
3387 msg
->op
= (uint32_t *)reallocf(msg
->op
, msg
->count
* sizeof(uint32_t));
3388 if (msg
->op
== NULL
) return -1;
3400 * asl_search: Search for messages matching the criteria described
3401 * by the aslmsg. The caller should set the attributes to match using
3402 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
3403 * used for attributes set with asl_set().
3405 * returns: a set of messages that can be iterated over using aslresp_next(),
3406 * and the values can be retrieved using aslresp_get.
3410 * This routine searches the ASL datastore on disk (/var/log/asl).
3411 * It is called my asl_search if syslogd is not running or if syslogd
3412 * indicates that an in-memory store is not being used.
3415 _asl_search_store(aslclient ac
, aslmsg a
)
3417 asl_search_result_t query
, *out
;
3418 asl_msg_t
*q
, *qlist
[1];
3420 uint64_t last_id
, start_id
;
3423 if (a
== NULL
) return NULL
;
3427 /* check for "ASLMessageId >[=] n" and set start_id */
3429 x
= _asl_msg_index(q
, ASL_KEY_MSG_ID
);
3430 if ((x
!= (uint32_t)-1) && (q
->val
[x
] != NULL
) && (q
->op
!= NULL
) && (q
->op
[x
] & ASL_QUERY_OP_GREATER
))
3432 if (q
->op
[x
] & ASL_QUERY_OP_EQUAL
) start_id
= atoi(q
->val
[x
]);
3433 else start_id
= atoi(q
->val
[x
]) + 1;
3437 status
= asl_store_open_read(NULL
, &store
);
3438 if (status
!= 0) return NULL
;
3439 if (store
== NULL
) return NULL
;
3444 qlist
[0] = (asl_msg_t
*)a
;
3445 memset(&query
, 0, sizeof(asl_search_result_t
));
3449 status
= asl_store_match(store
, &query
, &out
, &last_id
, start_id
, 0, 1);
3450 asl_store_close(store
);
3456 _asl_search_concat_results(asl_search_result_t
*batch
, asl_search_result_t
**out
)
3460 if (out
== NULL
) return ASL_STATUS_FAILED
;
3462 /* nothing to do if batch is NULL or contains no messages */
3463 if (batch
== NULL
) return 0;
3464 if (batch
->count
== 0)
3466 aslresponse_free(batch
);
3470 if (*out
== NULL
) *out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
3473 aslresponse_free(batch
);
3474 return ASL_STATUS_FAILED
;
3477 if ((*out
)->count
== 0)
3479 (*out
)->msg
= (asl_msg_t
**)calloc(batch
->count
, sizeof(asl_msg_t
*));
3483 (*out
)->msg
= (asl_msg_t
**)reallocf((*out
)->msg
, ((*out
)->count
+ batch
->count
) * sizeof(asl_msg_t
*));
3486 if ((*out
)->msg
== NULL
)
3488 aslresponse_free(batch
);
3491 return ASL_STATUS_FAILED
;
3494 for (i
= 0, j
= (*out
)->count
; i
< batch
->count
; i
++, j
++) (*out
)->msg
[j
] = batch
->msg
[i
];
3496 (*out
)->count
+= batch
->count
;
3499 return ASL_STATUS_OK
;
3503 _asl_search_memory(aslclient ac
, aslmsg a
)
3505 asl_search_result_t
*batch
, *out
;
3506 char *qstr
, *str
, *res
;
3507 uint32_t i
, len
, reslen
, status
;
3508 uint64_t cmax
, qmin
;
3509 kern_return_t kstatus
;
3510 security_token_t sec
;
3513 if (a
== NULL
) return 0;
3515 _asl_get_global_server_port();
3516 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
3519 qstr
= asl_msg_to_string((asl_msg_t
*)a
, &len
);
3524 asprintf(&str
, "0\n");
3529 asprintf(&str
, "1\n%s\n", qstr
);
3536 _asl_release_global_server_port();
3541 * Fetch a batch of results each time through the loop.
3542 * Fetching small batches rebuces the load on syslogd.
3554 status
= ASL_STATUS_OK
;
3556 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
3557 if (kstatus
!= KERN_SUCCESS
)
3559 _asl_release_global_server_port();
3563 memmove(vmstr
, str
, len
);
3566 kstatus
= _asl_server_query(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
3567 if (kstatus
!= KERN_SUCCESS
) break;
3568 if (res
== NULL
) break;
3570 batch
= asl_list_from_string(res
);
3571 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
3573 status
= _asl_search_concat_results(batch
, &out
);
3574 if (status
!= ASL_STATUS_OK
) break;
3575 if (i
< FETCH_BATCH
) break;
3577 if (cmax
> qmin
) qmin
= cmax
+ 1;
3582 _asl_release_global_server_port();
3587 asl_store_location()
3589 kern_return_t kstatus
;
3591 uint32_t reslen
, status
;
3593 security_token_t sec
;
3595 _asl_get_global_server_port();
3596 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
3603 status
= ASL_STATUS_OK
;
3605 kstatus
= _asl_server_query(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
3606 _asl_release_global_server_port();
3608 /* res should never be returned, but just to be certain we don't leak VM ... */
3609 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
3611 if (kstatus
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
;
3613 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
3614 return ASL_STORE_LOCATION_FILE
;
3618 asl_search(aslclient ac
, aslmsg a
)
3621 asl_search_result_t
*out
;
3623 /* prevents fetching and destroying the send right twice if nobody has already lookup up the port */
3624 _asl_get_global_server_port();
3626 where
= asl_store_location();
3627 if (where
== ASL_STORE_LOCATION_FILE
) out
= _asl_search_store(ac
, a
);
3628 else out
= _asl_search_memory(ac
, a
);
3630 _asl_release_global_server_port();
3635 * aslresponse_next: Iterate over responses returned from asl_search()
3636 * a: a response returned from asl_search();
3637 * returns: The next log message (an aslmsg) or NULL on failure
3640 aslresponse_next(aslresponse r
)
3642 asl_search_result_t
*res
;
3645 res
= (asl_search_result_t
*)r
;
3646 if (res
== NULL
) return NULL
;
3648 if (res
->curr
>= res
->count
) return NULL
;
3649 m
= res
->msg
[res
->curr
];
3656 * aslresponse_free: Free a response returned from asl_search()
3657 * a: a response returned from asl_search()
3660 aslresponse_free(aslresponse r
)
3662 asl_search_result_t
*res
;
3665 res
= (asl_search_result_t
*)r
;
3666 if (res
== NULL
) return;
3668 for (i
= 0; i
< res
->count
; i
++) asl_free(res
->msg
[i
]);
3674 asl_syslog_faciliy_name_to_num(const char *name
)
3676 if (name
== NULL
) return -1;
3678 if (strcaseeq(name
, "auth")) return LOG_AUTH
;
3679 if (strcaseeq(name
, "authpriv")) return LOG_AUTHPRIV
;
3680 if (strcaseeq(name
, "cron")) return LOG_CRON
;
3681 if (strcaseeq(name
, "daemon")) return LOG_DAEMON
;
3682 if (strcaseeq(name
, "ftp")) return LOG_FTP
;
3683 if (strcaseeq(name
, "install")) return LOG_INSTALL
;
3684 if (strcaseeq(name
, "kern")) return LOG_KERN
;
3685 if (strcaseeq(name
, "lpr")) return LOG_LPR
;
3686 if (strcaseeq(name
, "mail")) return LOG_MAIL
;
3687 if (strcaseeq(name
, "netinfo")) return LOG_NETINFO
;
3688 if (strcaseeq(name
, "remoteauth")) return LOG_REMOTEAUTH
;
3689 if (strcaseeq(name
, "news")) return LOG_NEWS
;
3690 if (strcaseeq(name
, "security")) return LOG_AUTH
;
3691 if (strcaseeq(name
, "syslog")) return LOG_SYSLOG
;
3692 if (strcaseeq(name
, "user")) return LOG_USER
;
3693 if (strcaseeq(name
, "uucp")) return LOG_UUCP
;
3694 if (strcaseeq(name
, "local0")) return LOG_LOCAL0
;
3695 if (strcaseeq(name
, "local1")) return LOG_LOCAL1
;
3696 if (strcaseeq(name
, "local2")) return LOG_LOCAL2
;
3697 if (strcaseeq(name
, "local3")) return LOG_LOCAL3
;
3698 if (strcaseeq(name
, "local4")) return LOG_LOCAL4
;
3699 if (strcaseeq(name
, "local5")) return LOG_LOCAL5
;
3700 if (strcaseeq(name
, "local6")) return LOG_LOCAL6
;
3701 if (strcaseeq(name
, "local7")) return LOG_LOCAL7
;
3702 if (strcaseeq(name
, "launchd")) return LOG_LAUNCHD
;
3708 asl_syslog_faciliy_num_to_name(int n
)
3710 if (n
< 0) return NULL
;
3712 if (n
== LOG_AUTH
) return "auth";
3713 if (n
== LOG_AUTHPRIV
) return "authpriv";
3714 if (n
== LOG_CRON
) return "cron";
3715 if (n
== LOG_DAEMON
) return "daemon";
3716 if (n
== LOG_FTP
) return "ftp";
3717 if (n
== LOG_INSTALL
) return "install";
3718 if (n
== LOG_KERN
) return "kern";
3719 if (n
== LOG_LPR
) return "lpr";
3720 if (n
== LOG_MAIL
) return "mail";
3721 if (n
== LOG_NETINFO
) return "netinfo";
3722 if (n
== LOG_REMOTEAUTH
) return "remoteauth";
3723 if (n
== LOG_NEWS
) return "news";
3724 if (n
== LOG_AUTH
) return "security";
3725 if (n
== LOG_SYSLOG
) return "syslog";
3726 if (n
== LOG_USER
) return "user";
3727 if (n
== LOG_UUCP
) return "uucp";
3728 if (n
== LOG_LOCAL0
) return "local0";
3729 if (n
== LOG_LOCAL1
) return "local1";
3730 if (n
== LOG_LOCAL2
) return "local2";
3731 if (n
== LOG_LOCAL3
) return "local3";
3732 if (n
== LOG_LOCAL4
) return "local4";
3733 if (n
== LOG_LOCAL5
) return "local5";
3734 if (n
== LOG_LOCAL6
) return "local6";
3735 if (n
== LOG_LOCAL7
) return "local7";
3736 if (n
== LOG_LAUNCHD
) return "launchd";
3742 * utility for converting a time string into a time_t
3743 * we only deal with the following formats:
3744 * Canonical form YYYY.MM.DD hh:mm:ss UTC
3745 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
3746 * absolute form - # seconds since the epoch (e.g. 1095789191)
3747 * relative time - seconds before or after now (e.g. -300, +43200)
3748 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
3751 #define CANONICAL_TIME_REX "^[0-9][0-9][0-9][0-9].[01]?[0-9].[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9][ ]+UTC$"
3752 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
3753 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
3754 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
3756 #define SECONDS_PER_MINUTE 60
3757 #define SECONDS_PER_HOUR 3600
3758 #define SECONDS_PER_DAY 86400
3759 #define SECONDS_PER_WEEK 604800
3762 * We use the last letter in the month name to determine
3763 * the month number (0-11). There are two collisions:
3764 * Jan and Jun both end in n
3765 * Mar and Apr both end in r
3766 * In these cases we check the second letter.
3768 * The MTH_LAST array maps the last letter to a number.
3770 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};
3779 if (s
[2] > 90) v8
= s
[2] - 'a';
3780 else v8
= s
[2] - 'A';
3782 if ((v8
< 0) || (v8
> 25)) return -1;
3785 if (v8
< 0) return -1;
3788 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
3789 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
3794 asl_parse_time(const char *in
)
3796 int len
, y
, status
, rflags
;
3798 time_t tick
, delta
, factor
;
3800 static regex_t rex_canon
, rex_ctime
, rex_abs
, rex_rel
;
3801 static int init_canon
= 0;
3802 static int init_ctime
= 0;
3803 static int init_abs
= 0;
3804 static int init_rel
= 0;
3806 if (in
== NULL
) return -1;
3808 rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
3810 if (init_canon
== 0)
3812 memset(&rex_canon
, 0, sizeof(regex_t
));
3813 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
3814 if (status
!= 0) return -1;
3818 if (init_ctime
== 0)
3820 memset(&rex_ctime
, 0, sizeof(regex_t
));
3821 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
3822 if (status
!= 0) return -1;
3828 memset(&rex_abs
, 0, sizeof(regex_t
));
3829 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
3830 if (status
!= 0) return -1;
3836 memset(&rex_rel
, 0, sizeof(regex_t
));
3837 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
3838 if (status
!= 0) return -1;
3842 len
= strlen(in
) + 1;
3844 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
3847 * Absolute time (number of seconds since the epoch)
3850 if (str
== NULL
) return -1;
3852 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
3859 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
3862 * Reletive time (number of seconds before or after right now)
3865 if (str
== NULL
) return -1;
3869 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
3873 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
3876 factor
= SECONDS_PER_MINUTE
;
3878 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
3881 factor
= SECONDS_PER_HOUR
;
3883 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
3886 factor
= SECONDS_PER_DAY
;
3888 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
3891 factor
= SECONDS_PER_WEEK
;
3895 delta
= factor
* atol(str
);
3902 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
3904 memset(&t
, 0, sizeof(struct tm
));
3906 if (str
== NULL
) return -1;
3912 t
.tm_year
= atoi(x
) - 1900;
3918 t
.tm_mon
= atoi(x
) - 1;
3924 t
.tm_mday
= atoi(x
);
3927 for (x
= p
+ 1; *x
== ' '; x
++);
3930 t
.tm_hour
= atoi(x
);
3947 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
3949 /* We assume it's in the current year */
3950 memset(&t
, 0, sizeof(struct tm
));
3952 gmtime_r(&tick
, &t
);
3955 memset(&t
, 0, sizeof(struct tm
));
3957 if (str
== NULL
) return -1;
3960 t
.tm_mon
= _month_num(str
);
3961 if (t
.tm_mon
< 0) return -1;
3963 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
3966 t
.tm_mday
= atoi(x
);
3969 for (x
= p
+ 1; *x
== ' '; x
++);
3972 t
.tm_hour
= atoi(x
);
3993 #endif /* BUILDING_VARIANT */