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 ASL_SERVICE_NAME "com.apple.system.logger"
53 #define streq(A, B) (strcmp(A, B) == 0)
54 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
56 #define forever for(;;)
76 #define XML_TAG_STRING 1
77 #define XML_TAG_DATA 2
79 #define FETCH_BATCH 256
82 time_t asl_parse_time(const char *);
83 const char *asl_syslog_faciliy_num_to_name(int n
);
84 __private_extern__ asl_client_t
*_asl_open_default();
87 uint32_t notify_register_plain(const char *name
, int *out_token
);
90 int _asl_server_socket(int *sock
, struct sockaddr_un
*server
);
91 int asl_is_utf8(const char *str
);
92 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
94 /* character encoding lengths */
95 static const uint8_t char_encode_len
[128] =
97 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,
98 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,
99 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,
100 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
103 static const char *cvis_7_13
= "abtnvfr";
111 pthread_mutex_t lock
;
115 #ifndef BUILDING_VARIANT
116 __private_extern__ _asl_global_t _asl_global
= {0, -1, -1, NULL
, PTHREAD_MUTEX_INITIALIZER
, NULL
};
118 static mach_port_t asl_server_port
= MACH_PORT_NULL
;
121 _asl_connect(asl_client_t
*asl
)
123 if (asl
->sock
>= 0) return 0;
125 return _asl_server_socket(&asl
->sock
, &asl
->server
);
129 _asl_notify_open(int do_lock
)
135 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
137 _asl_global
.notify_count
++;
139 if (_asl_global
.notify_token
!= -1)
141 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
147 prefix
= NOTIFY_PREFIX_USER
;
148 if (getuid() == 0) prefix
= NOTIFY_PREFIX_SYSTEM
;
150 if (_asl_global
.master_token
== -1)
152 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
153 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
156 asprintf(¬ify_name
, "%s.%d", prefix
, getpid());
158 if (notify_name
!= NULL
)
160 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
162 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
165 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
167 if (_asl_global
.notify_token
== -1) return -1;
174 pthread_mutex_lock(&_asl_global
.lock
);
176 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
178 if (_asl_global
.notify_count
> 0)
180 pthread_mutex_unlock(&_asl_global
.lock
);
184 if (_asl_global
.master_token
> 0) notify_cancel(_asl_global
.master_token
);
185 _asl_global
.master_token
= -1;
187 if (_asl_global
.notify_token
> 0) notify_cancel(_asl_global
.notify_token
);
188 _asl_global
.notify_token
= -1;
190 pthread_mutex_unlock(&_asl_global
.lock
);
194 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
199 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
210 if (asl
->options
& ASL_OPT_NO_DELAY
)
212 if (_asl_connect(asl
) < 0)
223 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
227 asl
->name
= strdup(ident
);
228 if (asl
->name
== NULL
)
237 name
= *(*_NSGetArgv());
240 x
= strrchr(name
, '/');
243 asl
->name
= strdup(x
);
244 if (asl
->name
== NULL
)
253 asl
->facility
= NULL
;
254 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
255 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
256 if (asl
->facility
== NULL
)
263 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
265 if (asl
->options
& ASL_OPT_STDERR
) asl_add_output((aslclient
)asl
, fileno(stderr
), ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
267 return (aslclient
)asl
;
271 asl_close(aslclient ac
)
276 asl
= (asl_client_t
*)ac
;
277 if (asl
== NULL
) return;
279 if (asl
->sock
>= 0) close(asl
->sock
);
280 if (asl
->name
!= NULL
) free(asl
->name
);
281 if (asl
->facility
!= NULL
) free(asl
->facility
);
282 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_close();
283 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
285 if (asl
->fd_mfmt
!= NULL
)
287 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
291 if (asl
->fd_tfmt
!= NULL
)
293 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
297 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
299 memset(asl
, 0, sizeof(asl_client_t
));
303 __private_extern__ asl_client_t
*
306 pthread_mutex_lock(&_asl_global
.lock
);
307 if (_asl_global
.asl
!= NULL
)
309 pthread_mutex_unlock(&_asl_global
.lock
);
310 return _asl_global
.asl
;
314 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
315 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
316 * which locks _asl_global.lock.
318 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
320 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
321 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
323 /* Now call _asl_notify_open(0) to finish the work */
326 pthread_mutex_unlock(&_asl_global
.lock
);
328 return _asl_global
.asl
;
332 _asl_msg_index(asl_msg_t
*msg
, const char *k
)
336 if (msg
== NULL
) return (uint32_t)-1;
337 if (k
== NULL
) return (uint32_t)-1;
339 for (i
= 0; i
< msg
->count
; i
++)
341 if (msg
->key
[i
] == NULL
) continue;
342 if (streq(msg
->key
[i
], k
)) return i
;
349 _asl_encode_char(char **m
, uint32_t *x
, uint32_t c
, uint32_t encode
, uint32_t encode_space
)
358 /* NUL is not allowed */
361 /* Meta chars get \M prefix */
364 /* except meta-space, which is \240 */
384 /* space is either ' ' or \s */
387 if (encode_space
== 0)
403 if ((meta
== 0) && (c
== 92))
412 /* [ and ] are escaped in ASL encoding */
413 if ((encode
== ASL_ENCODE_ASL
) && (meta
== 0) && ((c
== 91) || (c
== 93)))
438 /* 33-126 are printable (add a '-' prefix for meta) */
439 if ((c
>= 33) && (c
<= 126))
453 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
454 if ((meta
== 0) && (c
>= 7) && (c
<= 13))
457 *p
++ = cvis_7_13
[c
- 7];
463 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
464 if ((c
>= 0) && (c
<= 31))
483 _asl_append_string(char **m
, uint32_t *x
, const char *s
, uint32_t encode
, uint32_t escspace
)
485 uint32_t i
, n
, spextra
;
489 if (m
== NULL
) return;
490 if (x
== NULL
) return;
491 if (s
== NULL
) return;
493 if (encode
== ASL_ENCODE_NONE
)
495 /* no encoding - just allocate enough space and copy the string */
507 *m
= reallocf(*m
, n
+ (*x
));
510 if (*m
== NULL
) return;
512 memcpy((*m
) + (*x
) - 1, s
, n
+ 1);
517 else if (encode
== ASL_ENCODE_SAFE
)
520 * Minor encoding to reduce the likelyhood of spoof attacks.
522 * - append a tab after newlines
523 * - translate \r to newline & append a tab
524 * - map backspace to ^H
526 * Note that there may be UTF-8 characters that could be used in a spoof
527 * attack that we don't check. Caveat Reador.
530 for (i
= 0; s
[i
] != '\0'; i
++)
534 if ((c
== 10) || (c
== 13) || (c
== 8)) n
++;
546 *m
= reallocf(*m
, n
+ (*x
));
549 if (*m
== NULL
) return;
553 for (i
= 0; s
[i
] != '\0'; i
++)
556 if ((c
== 10) || (c
== 13))
580 if (escspace
!= 0) spextra
= 1;
583 for (i
= 0; s
[i
] != '\0'; i
++)
591 else if ((c
== 91) || (c
== 93))
593 if (encode
== ASL_ENCODE_ASL
) n
+= 2;
598 n
+= char_encode_len
[c
];
599 if (c
== 32) n
+= spextra
;
612 *m
= reallocf(*m
, n
+ (*x
));
615 if (*m
== NULL
) return;
617 for (i
= 0; s
[i
] != '\0'; i
++)
620 _asl_encode_char(m
, x
, c
, encode
, escspace
);
627 _asl_append_xml_string(char **m
, uint32_t *x
, char *s
)
633 if (m
== NULL
) return;
634 if (x
== NULL
) return;
635 if (s
== NULL
) return;
638 for (i
= 0; s
[i
] != '\0'; i
++)
643 * XML wants & < > " and '
644 * We use &#xnn; for control chars.
645 * Everything else just gets printed "as is" (we know the input is UTF8)
647 if (c
== '&') n
+= 5;
648 else if (c
== '<') n
+= 4;
649 else if (c
== '>') n
+= 4;
650 else if (c
== '"') n
+= 6;
651 else if (c
== '\'') n
+= 6;
652 else if (iscntrl(c
)) n
+= 6;
665 *m
= reallocf(*m
, n
+ (*x
));
668 if (*m
== NULL
) return;
670 for (i
= 0; s
[i
] != '\0'; i
++)
677 memcpy(p
, "&", 5);
685 memcpy(p
, "<", 4);
693 memcpy(p
, ">", 4);
701 memcpy(p
, """, 6);
709 memcpy(p
, "'", 6);
716 snprintf(tmp
, sizeof(tmp
), "&#x%02hhu;", c
);
736 _asl_append_xml_tag(char **m
, uint32_t *x
, int tag
, char *s
)
740 if (m
== NULL
) return;
741 if (x
== NULL
) return;
743 if (tag
== XML_TAG_KEY
)
745 _asl_append_string(m
, x
, "\t\t<key>", ASL_ENCODE_NONE
, 0);
746 _asl_append_xml_string(m
, x
, s
);
747 _asl_append_string(m
, x
, "</key>\n", ASL_ENCODE_NONE
, 0);
751 if (tag
== XML_TAG_STRING
)
753 _asl_append_string(m
, x
, "\t\t<string>", ASL_ENCODE_NONE
, 0);
754 _asl_append_xml_string(m
, x
, s
);
755 _asl_append_string(m
, x
, "</string>\n", ASL_ENCODE_NONE
, 0);
759 if (tag
== XML_TAG_DATA
)
761 _asl_append_string(m
, x
, "\t\t<data>", ASL_ENCODE_NONE
, 0);
762 b64
= (char *)asl_b64_encode((uint8_t *)s
, strlen(s
));
765 _asl_append_string(m
, x
, b64
, ASL_ENCODE_NONE
, 0);
768 _asl_append_string(m
, x
, "</data>\n", ASL_ENCODE_NONE
, 0);
774 _asl_append_op(char **m
, uint32_t *x
, uint32_t op
)
779 if (m
== NULL
) return;
780 if (x
== NULL
) return;
782 if (op
== ASL_QUERY_OP_NULL
) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
785 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
787 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
789 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
791 if (op
& ASL_QUERY_OP_PREFIX
)
793 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
794 else opstr
[i
++] = 'A';
796 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
798 switch (op
& ASL_QUERY_OP_TRUE
)
800 case ASL_QUERY_OP_EQUAL
:
803 case ASL_QUERY_OP_GREATER
:
806 case ASL_QUERY_OP_GREATER_EQUAL
:
810 case ASL_QUERY_OP_LESS
:
813 case ASL_QUERY_OP_LESS_EQUAL
:
817 case ASL_QUERY_OP_NOT_EQUAL
:
820 case ASL_QUERY_OP_TRUE
:
827 if (i
== 0) return _asl_append_string(m
, x
, ".", ASL_ENCODE_NONE
, 0);
830 return _asl_append_string(m
, x
, opstr
, ASL_ENCODE_NONE
, 0);
834 _asl_time_string(int fmt
, const char *str
)
844 if (str
!= NULL
) tick
= asl_parse_time(str
);
848 asprintf(&out
, "%lu", tick
);
855 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
);
861 ltime
= ctime_r(&tick
, ltbuf
);
862 if (ltime
== NULL
) return NULL
;
864 asprintf(&out
, "%s", ltime
);
872 _asl_msg_to_string_time_fmt(asl_msg_t
*msg
, uint32_t *len
, int tf
)
879 if (msg
== NULL
) return NULL
;
887 if (out
== NULL
) return NULL
;
892 for (i
= 0; i
< msg
->count
; i
++)
894 if (msg
->key
[i
] == NULL
) continue;
895 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
896 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
898 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
900 if ((tf
!= TFMT_SEC
) && (!strcmp(msg
->key
[i
], ASL_KEY_TIME
)))
902 s
= _asl_time_string(tf
, msg
->val
[i
]);
905 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
906 _asl_append_string(&out
, &outlen
, s
, ASL_ENCODE_ASL
, 0);
909 else if (msg
->val
[i
] != NULL
)
911 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
912 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
915 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
918 _asl_append_string(&out
, &outlen
, "\n", ASL_ENCODE_NONE
, 0);
925 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
932 if (msg
== NULL
) return NULL
;
938 if (msg
->type
== ASL_TYPE_QUERY
)
940 _asl_append_string(&out
, &outlen
, "Q ", ASL_ENCODE_NONE
, 0);
941 if (out
== NULL
) return NULL
;
946 if (out
== NULL
) return NULL
;
951 for (i
= 0; i
< msg
->count
; i
++)
953 if (msg
->key
[i
] == NULL
) continue;
955 if (i
> 0) _asl_append_string(&out
, &outlen
, " [", ASL_ENCODE_NONE
, 0);
956 else _asl_append_string(&out
, &outlen
, "[", ASL_ENCODE_NONE
, 0);
958 if (msg
->type
== ASL_TYPE_QUERY
)
960 _asl_append_op(&out
, &outlen
, msg
->op
[i
]);
961 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
964 _asl_append_string(&out
, &outlen
, msg
->key
[i
], ASL_ENCODE_ASL
, 1);
966 if (msg
->val
[i
] != NULL
)
968 _asl_append_string(&out
, &outlen
, " ", ASL_ENCODE_NONE
, 0);
969 _asl_append_string(&out
, &outlen
, msg
->val
[i
], ASL_ENCODE_ASL
, 0);
972 _asl_append_string(&out
, &outlen
, "]", ASL_ENCODE_NONE
, 0);
980 _asl_msg_op_from_string(char *o
)
984 op
= ASL_QUERY_OP_NULL
;
986 if (o
== NULL
) return op
;
988 for (i
= 0; o
[i
] != '\0'; i
++)
990 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
991 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
992 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
993 if (o
[i
] == 'N') op
|= ASL_QUERY_OP_NUMERIC
;
994 if (o
[i
] == 'S') op
|= ASL_QUERY_OP_SUBSTRING
;
995 if (o
[i
] == 'A') op
|= ASL_QUERY_OP_PREFIX
;
996 if (o
[i
] == 'Z') op
|= ASL_QUERY_OP_SUFFIX
;
997 if (o
[i
] == '<') op
|= ASL_QUERY_OP_LESS
;
998 if (o
[i
] == '>') op
|= ASL_QUERY_OP_GREATER
;
999 if (o
[i
] == '=') op
|= ASL_QUERY_OP_EQUAL
;
1000 if (o
[i
] == '!') op
|= ASL_QUERY_OP_NOT_EQUAL
;
1001 if (o
[i
] == 'T') op
|= ASL_QUERY_OP_TRUE
;
1008 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
1010 char *str
, *out
, c
, oval
;
1011 uint32_t i
, len
, n
, outlen
;
1015 if (p
== NULL
) return NULL
;
1016 if (*p
== NULL
) return NULL
;
1017 if (**p
== '\0') return NULL
;
1019 /* skip one space if it's there (word separator) */
1020 if (**p
== ' ') (*p
)++;
1022 /* skip leading white space */
1025 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
1028 if (**p
== '\0') return NULL
;
1029 if (**p
== '\n') return NULL
;
1040 if (out
== NULL
) return NULL
;
1047 /* scan for token and calulate it's length (input and decoded output len) */
1055 /* stop scanning when we hit a delimiter */
1056 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
1062 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
1067 if (str
[++len
] == '\0') return NULL
;
1071 if (str
[++len
] == '\0') return NULL
;
1072 if (str
[++len
] == '\0') return NULL
;
1074 else if ((c
>= '0') && (c
<= '3'))
1076 if (str
[++len
] == '\0') return NULL
;
1077 if (str
[++len
] == '\0') return NULL
;
1091 if ((len
== 0) && (**p
== ']'))
1096 if (out
== NULL
) return NULL
;
1105 out
= malloc(outlen
+ 1);
1106 if (out
== NULL
) return NULL
;
1109 for (i
= 0; i
< len
; i
++)
1166 if (str
[i
] == '?') out
[n
++] = 127;
1167 else out
[n
++] = str
[i
] - 64;
1176 if (str
[i
] == '?') out
[n
++] = 255;
1177 else out
[n
++] = str
[i
] + 64;
1182 out
[n
++] = str
[i
] + 128;
1192 else if ((c
>= '0') && (c
<= '3'))
1194 oval
= (c
- '0') * 64;
1198 if ((c
< '0') || (c
> '7'))
1205 oval
+= ((c
- '0') * 8);
1209 if ((c
< '0') || (c
> '7'))
1230 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
1241 asl_msg_from_string(const char *buf
)
1243 uint32_t tt
, type
, op
;
1244 char *k
, *v
, *o
, *p
;
1247 if (buf
== NULL
) return NULL
;
1249 type
= ASL_TYPE_MSG
;
1252 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1253 if (k
== NULL
) return NULL
;
1257 type
= ASL_TYPE_QUERY
;
1260 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1262 else if (tt
== TOKEN_INT
)
1264 /* Leading integer is a string length - skip it */
1266 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1267 if (k
== NULL
) return NULL
;
1270 msg
= calloc(1, sizeof(asl_msg_t
));
1271 if (msg
== NULL
) return NULL
;
1275 /* OPEN WORD [WORD [WORD]] CLOSE */
1278 op
= ASL_QUERY_OP_NULL
;
1280 if (tt
!= TOKEN_OPEN
)
1288 /* get op for query type */
1289 if (type
== ASL_TYPE_QUERY
)
1291 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
1292 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
1294 if (o
!= NULL
) free(o
);
1299 op
= _asl_msg_op_from_string(o
);
1303 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1304 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1305 if ((k
== NULL
) || (tt
!= TOKEN_WORD
))
1307 if (k
!= NULL
) free(k
);
1312 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
1313 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
1316 asl_set_query(msg
, k
, NULL
, op
);
1320 if (tt
== TOKEN_CLOSE
)
1322 asl_set_query(msg
, k
, NULL
, op
);
1324 else if (tt
== TOKEN_WORD
)
1326 asl_set_query(msg
, k
, v
, op
);
1330 if (k
!= NULL
) free(k
);
1331 if (v
!= NULL
) free(v
);
1336 if (k
!= NULL
) free(k
);
1337 if (v
!= NULL
) free(v
);
1339 if (tt
!= TOKEN_CLOSE
)
1341 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1342 if (k
== NULL
) break;
1344 if (tt
!= TOKEN_CLOSE
)
1353 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
1354 if (k
== NULL
) break;
1361 asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
)
1363 uint32_t i
, len
, newlen
;
1366 if (list
== NULL
) return NULL
;
1367 if (list
->count
== 0) return NULL
;
1368 if (list
->msg
== NULL
) return NULL
;
1371 asprintf(&out
, "%u\n", list
->count
);
1372 if (out
== NULL
) return NULL
;
1373 *outlen
= strlen(out
) + 1;
1375 for (i
= 0; i
< list
->count
; i
++)
1378 msgbuf
= asl_msg_to_string(list
->msg
[i
], &len
);
1386 newlen
= *outlen
+ len
;
1387 out
= reallocf(out
, newlen
);
1394 memmove((out
+ *outlen
- 1), msgbuf
, len
);
1395 out
[newlen
- 2] = '\n';
1396 out
[newlen
- 1] = '\0';
1405 asl_search_result_t
*
1406 asl_list_from_string(const char *buf
)
1410 asl_search_result_t
*out
;
1413 if (buf
== NULL
) return NULL
;
1417 if (n
== 0) return NULL
;
1419 out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1420 if (out
== NULL
) return NULL
;
1422 out
->msg
= (asl_msg_t
**)calloc(n
, sizeof(asl_msg_t
*));
1423 if (out
->msg
== NULL
)
1429 for (i
= 0; i
< n
; i
++)
1431 p
= strchr(p
, '\n');
1434 aslresponse_free((aslresponse
)out
);
1440 m
= asl_msg_from_string(p
);
1443 aslresponse_free((aslresponse
)out
);
1455 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1459 if (a
->count
!= b
->count
) return 0;
1461 for (i
= 0; i
< a
->count
; i
++)
1463 j
= _asl_msg_index(b
, a
->key
[i
]);
1464 if (j
== (uint32_t)-1) return 0;
1466 if (a
->val
[i
] == NULL
)
1468 if (b
->val
[j
] != NULL
) return 0;
1472 if (b
->val
[j
] == NULL
) return 0;
1473 if (strcmp(a
->val
[i
], b
->val
[j
])) return 0;
1476 if (a
->type
== ASL_TYPE_QUERY
)
1478 if (a
->op
[i
] != b
->op
[j
]) return 0;
1486 _asl_isanumber(char *s
)
1490 if (s
== NULL
) return 0;
1493 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1495 if (s
[i
] == '\0') return 0;
1497 for (; s
[i
] != '\0'; i
++)
1499 if (!isdigit(s
[i
])) return 0;
1506 _asl_msg_op_test(uint32_t op
, char *q
, char *m
, uint32_t n
)
1513 t
= op
& ASL_QUERY_OP_TRUE
;
1515 if (op
& ASL_QUERY_OP_REGEX
)
1517 memset(&rex
, 0, sizeof(regex_t
));
1519 rflags
= REG_EXTENDED
| REG_NOSUB
;
1520 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1522 if (regcomp(&rex
, q
, rflags
) != 0) return 0;
1523 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1528 if (op
& ASL_QUERY_OP_NUMERIC
)
1530 /* We assume the query contains a numeric string */
1531 if (_asl_isanumber(m
) == 0) return 0;
1538 case ASL_QUERY_OP_EQUAL
: return (nm
== nq
);
1539 case ASL_QUERY_OP_GREATER
: return (nm
> nq
);
1540 case ASL_QUERY_OP_GREATER_EQUAL
: return (nm
>= nq
);
1541 case ASL_QUERY_OP_LESS
: return (nm
< nq
);
1542 case ASL_QUERY_OP_LESS_EQUAL
: return (nm
<= nq
);
1543 case ASL_QUERY_OP_NOT_EQUAL
: return (nm
!= nq
);
1549 if (op
& ASL_QUERY_OP_CASEFOLD
)
1551 if (n
== 0) cmp
= strcasecmp(m
, q
);
1552 else cmp
= strncasecmp(m
, q
, n
);
1556 if (n
== 0) cmp
= strcmp(m
, q
);
1557 else cmp
= strncmp(m
, q
, n
);
1562 case ASL_QUERY_OP_EQUAL
: return (cmp
== 0);
1563 case ASL_QUERY_OP_GREATER
: return (cmp
> 0);
1564 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp
>= 0);
1565 case ASL_QUERY_OP_LESS
: return (cmp
< 0);
1566 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp
<= 0);
1567 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp
!= 0);
1575 _asl_msg_test_op_substr(uint32_t op
, char *q
, char *m
)
1577 uint32_t i
, d
, lm
, lq
;
1582 if (lq
> lm
) return 0;
1585 for (i
= 0; i
<= d
; i
++)
1587 if (_asl_msg_op_test(op
, q
, m
+ i
, lq
) != 0) return 1;
1594 _asl_msg_test_op_prefix(uint32_t op
, char *q
, char *m
)
1601 if (lq
> lm
) return 0;
1603 return _asl_msg_op_test(op
, q
, m
, lq
);
1607 _asl_msg_test_op_suffix(uint32_t op
, char *q
, char *m
)
1614 if (lq
> lm
) return 0;
1617 return _asl_msg_op_test(op
, q
, m
+ d
, lq
);
1621 _asl_msg_test_op(uint32_t op
, char *q
, char *m
)
1625 t
= op
& ASL_QUERY_OP_TRUE
;
1626 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1628 if (op
& ASL_QUERY_OP_PREFIX
)
1630 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_op_substr(op
, q
, m
);
1631 return _asl_msg_test_op_prefix(op
, q
, m
);
1633 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_op_suffix(op
, q
, m
);
1635 return _asl_msg_op_test(op
, q
, m
, 0);
1639 _asl_msg_test_time_op(uint32_t op
, char *q
, char *m
)
1644 uint32_t t
, do_numeric
;
1649 if ((op
& ASL_QUERY_OP_PREFIX
) || (op
& ASL_QUERY_OP_SUFFIX
) || (op
& ASL_QUERY_OP_REGEX
) || (op
& ASL_QUERY_OP_CASEFOLD
)) do_numeric
= 0;
1651 tq
= asl_parse_time(q
);
1652 if (tq
< 0) return _asl_msg_test_op(op
, q
, m
);
1654 tm
= asl_parse_time(m
);
1655 if (tm
< 0) return _asl_msg_test_op(op
, q
, m
);
1657 if (do_numeric
== 1)
1659 t
= op
& ASL_QUERY_OP_TRUE
;
1662 case ASL_QUERY_OP_EQUAL
:
1663 if (tm
== tq
) return 1;
1665 case ASL_QUERY_OP_GREATER
:
1666 if (tm
> tq
) return 1;
1668 case ASL_QUERY_OP_GREATER_EQUAL
:
1669 if (tm
>= tq
) return 1;
1671 case ASL_QUERY_OP_LESS
:
1672 if (tm
< tq
) return 1;
1674 case ASL_QUERY_OP_LESS_EQUAL
:
1675 if (tm
<= tq
) return 1;
1677 case ASL_QUERY_OP_NOT_EQUAL
:
1678 if (tm
!= tq
) return 1;
1687 memset(>ime
, 0, sizeof(struct tm
));
1688 gmtime_r(&tq
, >ime
);
1690 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
1692 asprintf(&vq
, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime
.tm_year
+ 1900, gtime
.tm_mon
+ 1, gtime
.tm_mday
, gtime
.tm_hour
, gtime
.tm_min
, gtime
.tm_sec
);
1693 if (vq
== NULL
) return 0;
1695 memset(>ime
, 0, sizeof(struct tm
));
1696 gmtime_r(&tm
, >ime
);
1698 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
1700 asprintf(&vm
, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime
.tm_year
+ 1900, gtime
.tm_mon
+ 1, gtime
.tm_mday
, gtime
.tm_hour
, gtime
.tm_min
, gtime
.tm_sec
);
1701 if (vm
== NULL
) return 0;
1703 cmp
= _asl_msg_test_op(op
, q
, m
);
1712 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
1718 for (i
= 0; i
< q
->count
; i
++)
1720 j
= _asl_msg_index(m
, q
->key
[i
]);
1721 if (j
== (uint32_t)-1) return 0;
1723 if (q
->val
[i
] == NULL
) continue;
1724 if (q
->op
== NULL
) continue;
1726 if ((q
->op
[i
] & ASL_QUERY_OP_TRUE
) == ASL_QUERY_OP_TRUE
) continue;
1728 if (m
->val
[j
] == NULL
) return 0;
1733 if (streq(q
->key
[i
], ASL_KEY_TIME
))
1735 cmp
= _asl_msg_test_time_op(q
->op
[i
], q
->val
[i
], m
->val
[j
]);
1739 cmp
= _asl_msg_test_op(q
->op
[i
], val
, m
->val
[j
]);
1742 if (cmp
== 0) return 0;
1749 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1751 if (a
== NULL
) return 0;
1752 if (b
== NULL
) return 0;
1754 if (a
->type
== b
->type
) return _asl_msg_equal(a
, b
);
1755 if (a
->type
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
);
1756 return _asl_msg_test(b
, a
);
1760 * asl_add_file: write log messages to the given file descriptor
1761 * Log messages will be written to this file as well as to the server.
1764 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
1767 int use_global_lock
;
1770 use_global_lock
= 0;
1771 asl
= (asl_client_t
*)ac
;
1774 asl
= _asl_open_default();
1775 if (asl
== NULL
) return -1;
1776 pthread_mutex_lock(&_asl_global
.lock
);
1777 use_global_lock
= 1;
1780 for (i
= 0; i
< asl
->fd_count
; i
++)
1782 if (asl
->fd_list
[i
] == fd
)
1784 /* update message format, time format, and text encoding */
1785 if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
1786 asl
->fd_mfmt
[i
] = NULL
;
1787 if (mfmt
!= NULL
) asl
->fd_mfmt
[i
] = strdup(mfmt
);
1789 if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
1790 asl
->fd_tfmt
[i
] = NULL
;
1791 if (tfmt
!= NULL
) asl
->fd_tfmt
[i
] = strdup(tfmt
);
1793 asl
->fd_encoding
[i
] = text_encoding
;
1795 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1800 if (asl
->fd_count
== 0)
1802 asl
->fd_list
= (int *)calloc(1, sizeof(int));
1803 asl
->fd_mfmt
= (char **)calloc(1, sizeof(char *));
1804 asl
->fd_tfmt
= (char **)calloc(1, sizeof(char *));
1805 asl
->fd_encoding
= (uint32_t *)calloc(1, sizeof(int));
1809 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, (1 + asl
->fd_count
) * sizeof(int));
1810 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, (1 + asl
->fd_count
) * sizeof(char *));
1811 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, (1 + asl
->fd_count
) * sizeof(char *));
1812 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, (1 + asl
->fd_count
) * sizeof(uint32_t));
1815 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
1817 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
1818 if (asl
->fd_mfmt
!= NULL
) free(asl
->fd_mfmt
);
1819 if (asl
->fd_tfmt
!= NULL
) free(asl
->fd_tfmt
);
1820 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
1822 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1826 asl
->fd_list
[asl
->fd_count
] = fd
;
1827 if (mfmt
!= NULL
) asl
->fd_mfmt
[asl
->fd_count
] = strdup(mfmt
);
1828 if (tfmt
!= NULL
) asl
->fd_tfmt
[asl
->fd_count
] = strdup(tfmt
);
1829 asl
->fd_encoding
[asl
->fd_count
] = text_encoding
;
1833 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1838 asl_add_log_file(aslclient ac
, int fd
)
1840 return asl_add_output(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
1844 * asl_remove_output: stop writing log messages to the given file descriptor
1847 asl_remove_output(aslclient ac
, int fd
)
1850 int x
, use_global_lock
;
1853 use_global_lock
= 0;
1854 asl
= (asl_client_t
*)ac
;
1857 asl
= _asl_open_default();
1858 if (asl
== NULL
) return -1;
1859 pthread_mutex_lock(&_asl_global
.lock
);
1860 use_global_lock
= 1;
1863 if (asl
->fd_count
== 0)
1865 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1870 for (i
= 0; i
< asl
->fd_count
; i
++)
1872 if (asl
->fd_list
[i
] == fd
)
1881 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1885 if (asl
->fd_mfmt
[x
] != NULL
) free(asl
->fd_mfmt
[x
]);
1886 if (asl
->fd_tfmt
[x
] != NULL
) free(asl
->fd_tfmt
[x
]);
1888 for (i
= x
+ 1; i
< asl
->fd_count
; i
++, x
++)
1890 asl
->fd_list
[x
] = asl
->fd_list
[i
];
1891 asl
->fd_mfmt
[x
] = asl
->fd_mfmt
[i
];
1892 asl
->fd_tfmt
[x
] = asl
->fd_tfmt
[i
];
1893 asl
->fd_encoding
[x
] = asl
->fd_encoding
[i
];
1898 if (asl
->fd_count
== 0)
1901 asl
->fd_list
= NULL
;
1904 asl
->fd_mfmt
= NULL
;
1907 asl
->fd_tfmt
= NULL
;
1909 free(asl
->fd_encoding
);
1910 asl
->fd_encoding
= NULL
;
1914 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, asl
->fd_count
* sizeof(int));
1915 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, asl
->fd_count
* sizeof(char *));
1916 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, asl
->fd_count
* sizeof(char *));
1917 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, asl
->fd_count
* sizeof(uint32_t));
1919 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
1921 if (asl
->fd_list
!= NULL
)
1924 asl
->fd_list
= NULL
;
1927 if (asl
->fd_mfmt
!= NULL
)
1929 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
1931 asl
->fd_mfmt
= NULL
;
1934 if (asl
->fd_tfmt
!= NULL
)
1936 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
1938 asl
->fd_tfmt
= NULL
;
1941 if (asl
->fd_encoding
!= NULL
)
1943 free(asl
->fd_encoding
);
1944 asl
->fd_encoding
= NULL
;
1948 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1953 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1958 asl_remove_log_file(aslclient ac
, int fd
)
1960 return asl_remove_output(ac
, fd
);
1964 asl_set_filter(aslclient ac
, int f
)
1966 int last
, use_global_lock
;
1969 use_global_lock
= 0;
1970 asl
= (asl_client_t
*)ac
;
1973 asl
= _asl_open_default();
1974 if (asl
== NULL
) return -1;
1975 pthread_mutex_lock(&_asl_global
.lock
);
1976 use_global_lock
= 1;
1982 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1987 * asl_key: examine attribute keys
1988 * returns the key of the nth attribute in a message (beginning at zero)
1989 * returns NULL if the message has fewer attributes
1992 asl_key(aslmsg a
, uint32_t n
)
1996 msg
= (asl_msg_t
*)a
;
1997 if (msg
== NULL
) return NULL
;
1999 if (n
>= msg
->count
) return NULL
;
2004 * asl_new: create a new log message.
2007 asl_new(uint32_t type
)
2012 msg
= calloc(1, sizeof(asl_msg_t
));
2013 if (msg
== NULL
) return NULL
;
2016 if (type
== ASL_TYPE_QUERY
) return (aslmsg
)msg
;
2019 * Defaut attributes are:
2031 msg
->key
= calloc(msg
->count
, sizeof(char *));
2032 if (msg
->key
== NULL
)
2038 msg
->val
= calloc(msg
->count
, sizeof(char *));
2039 if (msg
->val
== NULL
)
2047 msg
->key
[i
] = strdup(ASL_KEY_TIME
);
2048 if (msg
->key
[i
] == NULL
)
2055 msg
->key
[i
] = strdup(ASL_KEY_HOST
);
2056 if (msg
->key
[i
] == NULL
)
2063 msg
->key
[i
] = strdup(ASL_KEY_SENDER
);
2064 if (msg
->key
[i
] == NULL
)
2071 msg
->key
[i
] = strdup(ASL_KEY_PID
);
2072 if (msg
->key
[i
] == NULL
)
2079 msg
->key
[i
] = strdup(ASL_KEY_UID
);
2080 if (msg
->key
[i
] == NULL
)
2087 msg
->key
[i
] = strdup(ASL_KEY_GID
);
2088 if (msg
->key
[i
] == NULL
)
2095 msg
->key
[i
] = strdup(ASL_KEY_LEVEL
);
2096 if (msg
->key
[i
] == NULL
)
2103 msg
->key
[i
] = strdup(ASL_KEY_MSG
);
2104 if (msg
->key
[i
] == NULL
)
2114 * asl_get: get attribute values from a message
2116 * key: attribute key
2117 * returns the attribute value
2118 * returns NULL if the message does not contain the key
2121 asl_get(aslmsg a
, const char *key
)
2126 msg
= (asl_msg_t
*)a
;
2128 if (msg
== NULL
) return NULL
;
2130 i
= _asl_msg_index(msg
, key
);
2131 if (i
== (uint32_t)-1) return NULL
;
2135 #endif /* BUILDING_VARIANT */
2138 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
2141 * level: the log level of the associated message
2142 * format: A formating string followed by a list of arguments, like vprintf()
2143 * returns 0 for success, non-zero for failure
2146 asl_vlog(aslclient ac
, aslmsg a
, int level
, const char *format
, va_list ap
)
2148 int status
, saved_errno
;
2150 char *str
, *fmt
, *estr
;
2151 uint32_t i
, len
, elen
, expand
, my_msg
;
2154 asl
= (asl_client_t
*)ac
;
2158 * Initialize _asl_global so that asl_new will have global data.
2159 * Not strictly necessary, but helps performance.
2161 asl
= _asl_open_default();
2162 if (asl
== NULL
) return -1;
2165 saved_errno
= errno
;
2167 if (format
== NULL
) return -1;
2169 msg
= (asl_msg_t
*)a
;
2175 msg
= asl_new(ASL_TYPE_MSG
);
2176 if (msg
== NULL
) return -1;
2179 if (msg
->type
!= ASL_TYPE_MSG
) return -1;
2181 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
2182 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
2185 asprintf(&str
, "%d", level
);
2188 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2192 asl_set(msg
, ASL_KEY_LEVEL
, str
);
2195 /* insert strerror for %m */
2198 estr
= strdup(strerror(saved_errno
));
2201 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2209 elen
= strlen(estr
);
2211 for (i
= 0; format
[i
] != '\0'; i
++)
2213 if (format
[i
] == '%')
2215 if (format
[i
+1] == '\0') len
++;
2216 else if (format
[i
+1] == 'm')
2232 fmt
= (char *)format
;
2236 fmt
= malloc(len
+ 1);
2239 if (estr
!= NULL
) free(estr
);
2245 for (i
= 0; format
[i
] != '\0'; i
++)
2247 if (format
[i
] == '%')
2249 if (format
[i
+1] == '\0')
2252 else if (format
[i
+1] == 'm')
2254 memcpy(fmt
+len
, estr
, elen
);
2260 fmt
[len
++] = format
[i
++];
2261 fmt
[len
++] = format
[i
];
2264 else fmt
[len
++] = format
[i
];
2270 if (estr
!= NULL
) free(estr
);
2272 vasprintf(&str
, fmt
, ap
);
2273 if (expand
!= 0) free(fmt
);
2277 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2281 asl_set(msg
, ASL_KEY_MSG
, str
);
2284 status
= asl_send(ac
, (aslmsg
)msg
);
2286 if ((msg
!= NULL
) && (my_msg
!= 0)) asl_free(msg
);
2291 * asl_log: log a message with a particular log level
2293 * level: the log level
2294 * format: A formating string followed by a list of arguments, like printf()
2295 * returns 0 for success, non-zero for failure
2298 asl_log(aslclient ac
, aslmsg a
, int level
, const char *format
, ...)
2303 if (format
== NULL
) return -1;
2305 va_start(ap
, format
);
2306 status
= asl_vlog(ac
, a
, level
, format
, ap
);
2312 #ifndef BUILDING_VARIANT
2315 _asl_level_string(int level
)
2317 if (level
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
;
2318 if (level
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
;
2319 if (level
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
;
2320 if (level
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
;
2321 if (level
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
;
2322 if (level
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
;
2323 if (level
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
;
2324 if (level
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
;
2329 * format a message for printing
2330 * out parameter len returns string length including trailing NUL
2333 asl_format_message(aslmsg msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
2335 char *out
, *tstr
, *k
, c
[2];
2336 const char *hstr
, *sstr
, *pstr
, *mstr
, *lstr
, *rprc
, *rpid
, *v
;
2337 int i
, j
, l
, mf
, tf
, paren
, oval
, level
;
2342 if (msg
== NULL
) return NULL
;
2347 if (mfmt
== NULL
) mf
= MFMT_RAW
;
2348 else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf
= MFMT_RAW
;
2349 else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf
= MFMT_STD
;
2350 else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf
= MFMT_BSD
;
2351 else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf
= MFMT_XML
;
2352 else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf
= MFMT_MSG
;
2355 if (tfmt
== NULL
) tf
= TFMT_SEC
;
2356 else if (!strcmp(tfmt
, ASL_TIME_FMT_SEC
)) tf
= TFMT_SEC
;
2357 else if (!strcmp(tfmt
, ASL_TIME_FMT_UTC
)) tf
= TFMT_UTC
;
2358 else if (!strcmp(tfmt
, ASL_TIME_FMT_LCL
)) tf
= TFMT_LCL
;
2362 out
= _asl_msg_to_string_time_fmt((asl_msg_t
*)msg
, len
, tf
);
2368 mstr
= asl_get(msg
, ASL_KEY_MSG
);
2369 if (mstr
== NULL
) return NULL
;
2371 _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2372 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2377 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
2379 /* BSD: Mth dd hh:mm:ss host sender[pid]: message */
2380 /* BSD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]): message */
2381 /* STD: Mth dd hh:mm:ss host sender[pid] <Level>: message */
2382 /* STD: Mth dd hh:mm:ss host sender[pid] (refproc[refpid]) <Level>: message */
2384 v
= asl_get(msg
, ASL_KEY_TIME
);
2385 tstr
= _asl_time_string(tf
, v
);
2387 hstr
= asl_get(msg
, ASL_KEY_HOST
);
2388 sstr
= asl_get(msg
, ASL_KEY_SENDER
);
2389 pstr
= asl_get(msg
, ASL_KEY_PID
);
2390 mstr
= asl_get(msg
, ASL_KEY_MSG
);
2392 rprc
= asl_get(msg
, ASL_KEY_REF_PROC
);
2393 rpid
= asl_get(msg
, ASL_KEY_REF_PID
);
2399 lstr
= asl_get(msg
, ASL_KEY_LEVEL
);
2400 if (lstr
!= NULL
) level
= atoi(lstr
);
2405 _asl_append_string(&out
, len
, "0", ASL_ENCODE_NONE
, 0);
2409 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2413 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2415 if (hstr
== NULL
) _asl_append_string(&out
, len
, "unknown", ASL_ENCODE_NONE
, 0);
2416 else _asl_append_string(&out
, len
, hstr
, text_encoding
, 0);
2418 _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2420 if (sstr
== NULL
) _asl_append_string(&out
, len
, "unknown", ASL_ENCODE_NONE
, 0);
2421 else _asl_append_string(&out
, len
, sstr
, text_encoding
, 0);
2423 if ((pstr
!= NULL
) && (strcmp(pstr
, "-1")))
2425 _asl_append_string(&out
, len
, "[", ASL_ENCODE_NONE
, 0);
2426 _asl_append_string(&out
, len
, pstr
, ASL_ENCODE_NONE
, 0);
2427 _asl_append_string(&out
, len
, "]", ASL_ENCODE_NONE
, 0);
2430 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, " (", ASL_ENCODE_NONE
, 0);
2432 if (rprc
!= NULL
) _asl_append_string(&out
, len
, rprc
, text_encoding
, 0);
2435 _asl_append_string(&out
, len
, "[", ASL_ENCODE_NONE
, 0);
2436 _asl_append_string(&out
, len
, rpid
, ASL_ENCODE_NONE
, 0);
2437 _asl_append_string(&out
, len
, "]", ASL_ENCODE_NONE
, 0);
2440 if ((rprc
!= NULL
) || (rpid
!= NULL
)) _asl_append_string(&out
, len
, ")", ASL_ENCODE_NONE
, 0);
2444 _asl_append_string(&out
, len
, " <", ASL_ENCODE_NONE
, 0);
2445 _asl_append_string(&out
, len
, _asl_level_string(level
), ASL_ENCODE_NONE
, 0);
2446 _asl_append_string(&out
, len
, ">", ASL_ENCODE_NONE
, 0);
2449 _asl_append_string(&out
, len
, ": ", ASL_ENCODE_NONE
, 0);
2451 if (mstr
!= NULL
) _asl_append_string(&out
, len
, mstr
, text_encoding
, 0);
2453 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2459 _asl_append_string(&out
, len
, "\t<dict>\n", ASL_ENCODE_NONE
, 0);
2461 for (i
= 0; i
< msg
->count
; i
++)
2463 if (asl_is_utf8(msg
->key
[i
]) == 1)
2465 _asl_append_xml_tag(&out
, len
, XML_TAG_KEY
, msg
->key
[i
]);
2466 if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
2468 tstr
= _asl_time_string(tf
, msg
->val
[i
]);
2469 _asl_append_xml_tag(&out
, len
, XML_TAG_STRING
, tstr
);
2470 if (tstr
!= NULL
) free(tstr
);
2474 if (asl_is_utf8(msg
->val
[i
]) == 1) _asl_append_xml_tag(&out
, len
, XML_TAG_STRING
, msg
->val
[i
]);
2475 else _asl_append_xml_tag(&out
, len
, XML_TAG_DATA
, msg
->val
[i
]);
2480 _asl_append_string(&out
, len
, "\t</dict>\n", ASL_ENCODE_NONE
, 0);
2487 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2503 if (out
!= NULL
) free(out
);
2509 for (j
= i
; mfmt
[j
] != '\0'; j
++)
2512 if (mfmt
[j
] == '\\') c
[0] = mfmt
[++j
];
2513 else if ((paren
== 1) && (mfmt
[j
] ==')')) break;
2514 else if (mfmt
[j
] != ' ') c
[0] = mfmt
[j
];
2516 if (c
[0] == '\0') break;
2518 k
= reallocf(k
, l
+ 1);
2521 if (out
!= NULL
) free(out
);
2530 if (paren
== 1) j
++;
2534 v
= asl_get(msg
, k
);
2537 if (!strcmp(k
, ASL_KEY_TIME
))
2539 tstr
= _asl_time_string(tf
, v
);
2540 _asl_append_string(&out
, len
, tstr
, ASL_ENCODE_NONE
, 0);
2541 if (tstr
!= NULL
) free(tstr
);
2545 _asl_append_string(&out
, len
, (char *)v
, ASL_ENCODE_NONE
, 0);
2552 if (mfmt
[i
] == '\\')
2555 if (mfmt
[i
] == '$') _asl_append_string(&out
, len
, "$", ASL_ENCODE_NONE
, 0);
2556 else if (mfmt
[i
] == 'e') _asl_append_string(&out
, len
, "\e", ASL_ENCODE_NONE
, 0);
2557 else if (mfmt
[i
] == 's') _asl_append_string(&out
, len
, " ", ASL_ENCODE_NONE
, 0);
2558 else if (mfmt
[i
] == 'a') _asl_append_string(&out
, len
, "\a", ASL_ENCODE_NONE
, 0);
2559 else if (mfmt
[i
] == 'b') _asl_append_string(&out
, len
, "\b", ASL_ENCODE_NONE
, 0);
2560 else if (mfmt
[i
] == 'f') _asl_append_string(&out
, len
, "\f", ASL_ENCODE_NONE
, 0);
2561 else if (mfmt
[i
] == 'n') _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2562 else if (mfmt
[i
] == 'r') _asl_append_string(&out
, len
, "\r", ASL_ENCODE_NONE
, 0);
2563 else if (mfmt
[i
] == 't') _asl_append_string(&out
, len
, "\t", ASL_ENCODE_NONE
, 0);
2564 else if (mfmt
[i
] == 'v') _asl_append_string(&out
, len
, "\v", ASL_ENCODE_NONE
, 0);
2565 else if (mfmt
[i
] == '\'') _asl_append_string(&out
, len
, "\'", ASL_ENCODE_NONE
, 0);
2566 else if (mfmt
[i
] == '\\') _asl_append_string(&out
, len
, "\\", ASL_ENCODE_NONE
, 0);
2567 else if (isdigit(mfmt
[i
]))
2569 oval
= mfmt
[i
] - '0';
2570 if (isdigit(mfmt
[i
+1]))
2573 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2574 if (isdigit(mfmt
[i
+1]))
2577 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2581 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2586 if (mfmt
[i
] == '\0') break;
2588 _asl_append_string(&out
, len
, c
, ASL_ENCODE_NONE
, 0);
2591 _asl_append_string(&out
, len
, "\n", ASL_ENCODE_NONE
, 0);
2597 * asl_send: send a message
2598 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
2599 * has been used to set all of a message's attributes.
2601 * returns 0 for success, non-zero for failure
2604 asl_send(aslclient ac
, aslmsg msg
)
2606 char *str
, *out_raw
, *out
;
2607 uint32_t i
, len
, level
, lmask
, outstatus
, filter
, senderx
, facilityx
;
2612 struct timeval tval
;
2613 int status
, rc_filter
;
2615 int use_global_lock
;
2617 char hname
[_POSIX_HOST_NAME_MAX
];
2619 use_global_lock
= 0;
2620 asl
= (asl_client_t
*)ac
;
2623 asl
= _asl_open_default();
2624 if (asl
== NULL
) return -1;
2625 use_global_lock
= 1;
2628 if (msg
== NULL
) return 0;
2630 level
= ASL_LEVEL_DEBUG
;
2632 val
= asl_get(msg
, ASL_KEY_LEVEL
);
2633 if (val
!= NULL
) level
= atoi(val
);
2635 lmask
= ASL_FILTER_MASK(level
);
2637 filter
= asl
->filter
;
2640 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
2642 pthread_mutex_lock(&_asl_global
.lock
);
2644 if (_asl_global
.notify_token
>= 0)
2648 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
2649 if ((status
== NOTIFY_STATUS_OK
) && (v64
!= 0))
2656 if ((rc_filter
== 0) && (_asl_global
.master_token
>= 0))
2660 status
= notify_get_state(_asl_global
.master_token
, &v64
);
2661 if ((status
== NOTIFY_STATUS_OK
) && (v64
!= 0))
2667 pthread_mutex_unlock(&_asl_global
.lock
);
2671 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here
2674 memset(&tval
, 0, sizeof(struct timeval
));
2676 status
= gettimeofday(&tval
, NULL
);
2679 asprintf(&str
, "%lu", tval
.tv_sec
);
2682 asl_set(msg
, ASL_KEY_TIME
, str
);
2687 asprintf(&str
, "%lu", tval
.tv_usec
* 1000);
2690 asl_set(msg
, ASL_KEY_TIME_NSEC
, str
);
2698 asprintf(&str
, "%lu", tick
);
2701 asl_set(msg
, ASL_KEY_TIME
, str
);
2707 memset(&hname
, 0, _POSIX_HOST_NAME_MAX
);
2708 if (gethostname(hname
, _POSIX_HOST_NAME_MAX
) == 0)
2710 asl_set(msg
, ASL_KEY_HOST
, hname
);
2714 asprintf(&str
, "%u", getpid());
2717 asl_set(msg
, ASL_KEY_PID
, str
);
2722 asprintf(&str
, "%d", getuid());
2725 asl_set(msg
, ASL_KEY_UID
, str
);
2730 asprintf(&str
, "%u", getgid());
2733 asl_set(msg
, ASL_KEY_GID
, str
);
2737 senderx
= (uint32_t)-1;
2738 facilityx
= (uint32_t)-1;
2739 mt
= (asl_msg_t
*)msg
;
2741 for (i
= 0; (i
< mt
->count
) && ((senderx
== (uint32_t)-1) || (facilityx
== (uint32_t)-1)); i
++)
2743 if (mt
->key
[i
] == NULL
) continue;
2744 if (streq(mt
->key
[i
], ASL_KEY_SENDER
)) senderx
= i
;
2745 else if (streq(mt
->key
[i
], ASL_KEY_FACILITY
)) facilityx
= i
;
2749 * Set Sender if needed
2751 if ((senderx
== (uint32_t)-1) || (mt
->val
[senderx
] == NULL
))
2753 if ((ac
!= NULL
) && (ac
->name
!= NULL
))
2755 /* Use the Sender name from the client handle */
2756 asl_set(msg
, ASL_KEY_SENDER
, ac
->name
);
2760 /* Get the value for ASL_KEY_SENDER from cache */
2761 if (_asl_global
.sender
== NULL
)
2763 name
= *(*_NSGetArgv());
2766 x
= strrchr(name
, '/');
2770 pthread_mutex_lock(&_asl_global
.lock
);
2772 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
2773 pthread_mutex_unlock(&_asl_global
.lock
);
2777 if (_asl_global
.sender
!= NULL
) asl_set(msg
, ASL_KEY_SENDER
, _asl_global
.sender
);
2778 else asl_set(msg
, ASL_KEY_SENDER
, "Unknown");
2785 if ((facilityx
== (uint32_t)-1) || (mt
->val
[facilityx
] == NULL
))
2787 if ((ac
!= NULL
) && (ac
->facility
!= NULL
))
2789 /* Use the Facility name from the client handle */
2790 asl_set(msg
, ASL_KEY_FACILITY
, ac
->facility
);
2796 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
2798 if ((filter
!= 0) && ((filter
& lmask
) != 0))
2801 out_raw
= asl_msg_to_string((asl_msg_t
*)msg
, &len
);
2803 if ((out_raw
!= NULL
) && (len
!= 0))
2805 asprintf(&out
, "%10u %s\n", len
+ 1, out_raw
);
2808 if (asl
->sock
== -1) _asl_connect(asl
);
2812 status
= write(asl
->sock
, out
, len
+ 12);
2815 /* Write failed - try resetting */
2819 if (asl
->sock
>= 0) status
= write(asl
->sock
, out
, len
+ 12);
2820 if (status
< 0) outstatus
= -1;
2823 else outstatus
= -1;
2832 for (i
= 0; i
< asl
->fd_count
; i
++)
2834 if (asl
->fd_list
[i
] < 0) continue;
2837 out
= asl_format_message(msg
, asl
->fd_mfmt
[i
], asl
->fd_tfmt
[i
], asl
->fd_encoding
[i
], &len
);
2838 if (out
== NULL
) continue;
2840 status
= write(asl
->fd_list
[i
], out
, len
- 1);
2843 asl
->fd_list
[i
] = -1;
2850 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
2856 asl_msg_string(aslmsg a
)
2860 return asl_msg_to_string((asl_msg_t
*)a
, &len
);
2864 * asl_free: free a message
2865 * msg: an aslmsg to free
2873 msg
= (asl_msg_t
*)a
;
2875 if (msg
== NULL
) return;
2877 for (i
= 0; i
< msg
->count
; i
++)
2879 if (msg
->key
[i
] != NULL
) free(msg
->key
[i
]);
2880 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
2885 if (msg
->key
!= NULL
) free(msg
->key
);
2886 if (msg
->val
!= NULL
) free(msg
->val
);
2887 if (msg
->op
!= NULL
) free(msg
->op
);
2894 * Called if there's a malloc error while manipulating a message in asl_set_query.
2895 * Cleans up the key, kap, and op fields, sets count to zero.
2898 _asl_clear_msg(asl_msg_t
*msg
)
2902 if (msg
== NULL
) return;
2904 for (i
= 0; i
< msg
->count
; i
++)
2906 if (msg
->key
!= NULL
&& msg
->key
[i
] != NULL
) free(msg
->key
[i
]);
2907 if (msg
->val
!= NULL
&& msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
2910 if (msg
->key
!= NULL
) free(msg
->key
);
2911 if (msg
->val
!= NULL
) free(msg
->val
);
2912 if (msg
->op
!= NULL
) free(msg
->op
);
2922 * asl_set_query: set arbitrary parameters of a query
2923 * Similar to als_set, but allows richer query operations.
2924 * See ASL_QUERY_OP_* above.
2926 * key: attribute key
2927 * value: attribute value
2928 * op: an operation from the set above.
2929 * returns 0 for success, non-zero for failure
2932 asl_set_query(aslmsg a
, const char *key
, const char *val
, uint32_t op
)
2938 msg
= (asl_msg_t
*)a
;
2940 if (msg
== NULL
) return 0;
2942 if (key
== NULL
) return -1;
2946 if (streq(key
, ASL_KEY_LEVEL
))
2948 if (val
== NULL
) return -1;
2949 if (val
[0] == '\0') return -1;
2950 if ((val
[0] >= '0') && (val
[0] <= '9'))
2953 asprintf(&dv
, "%d", i
);
2954 if (dv
== NULL
) return -1;
2956 else if (!strcasecmp(val
, ASL_STRING_EMERG
))
2959 if (dv
== NULL
) return -1;
2961 else if (!strcasecmp(val
, ASL_STRING_ALERT
))
2964 if (dv
== NULL
) return -1;
2966 else if (!strcasecmp(val
, ASL_STRING_CRIT
))
2969 if (dv
== NULL
) return -1;
2971 else if (!strcasecmp(val
, ASL_STRING_ERR
))
2974 if (dv
== NULL
) return -1;
2976 else if (!strcasecmp(val
, ASL_STRING_WARNING
))
2979 if (dv
== NULL
) return -1;
2981 else if (!strcasecmp(val
, ASL_STRING_NOTICE
))
2984 if (dv
== NULL
) return -1;
2986 else if (!strcasecmp(val
, ASL_STRING_INFO
))
2989 if (dv
== NULL
) return -1;
2991 else if (!strcasecmp(val
, ASL_STRING_DEBUG
))
2994 if (dv
== NULL
) return -1;
2999 if ((dv
== NULL
) && (val
!= NULL
))
3002 if (dv
== NULL
) return -1;
3005 for (i
= 0; i
< msg
->count
; i
++)
3007 if (msg
->key
[i
] == NULL
) continue;
3009 if ((msg
->type
!= ASL_TYPE_QUERY
) && (streq(msg
->key
[i
], key
)))
3011 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3013 if (val
!= NULL
) msg
->val
[i
] = dv
;
3014 if (msg
->op
!= NULL
) msg
->op
[i
] = op
;
3019 if (msg
->count
== 0)
3021 msg
->key
= (char **)calloc(1, sizeof(char *));
3022 if (msg
->key
== NULL
)
3024 _asl_clear_msg(msg
);
3028 msg
->val
= (char **)calloc(1, sizeof(char *));
3029 if (msg
->val
== NULL
)
3031 _asl_clear_msg(msg
);
3035 if (msg
->type
== ASL_TYPE_QUERY
)
3037 msg
->op
= (uint32_t *)calloc(1, sizeof(uint32_t));
3038 if (msg
->op
== NULL
)
3040 _asl_clear_msg(msg
);
3047 msg
->key
= (char **)reallocf(msg
->key
, (msg
->count
+ 1) * sizeof(char *));
3048 if (msg
->key
== NULL
)
3050 _asl_clear_msg(msg
);
3054 msg
->val
= (char **)reallocf(msg
->val
, (msg
->count
+ 1) * sizeof(char *));
3055 if (msg
->val
== NULL
)
3057 _asl_clear_msg(msg
);
3061 if (msg
->type
== ASL_TYPE_QUERY
)
3063 msg
->op
= (uint32_t *)reallocf(msg
->op
, (msg
->count
+ 1) * sizeof(uint32_t));
3064 if (msg
->op
== NULL
)
3066 _asl_clear_msg(msg
);
3073 if (dk
== NULL
) return -1;
3075 msg
->key
[msg
->count
] = dk
;
3076 msg
->val
[msg
->count
] = dv
;
3077 if (msg
->op
!= NULL
) msg
->op
[msg
->count
] = op
;
3084 * asl_set: set attributes of a message
3086 * key: attribute key
3087 * value: attribute value
3088 * returns 0 for success, non-zero for failure
3091 asl_set(aslmsg msg
, const char *key
, const char *val
)
3093 return asl_set_query(msg
, key
, val
, 0);
3097 * asl_unset: remove attributes of a message
3099 * key: attribute key
3100 * returns 0 for success, non-zero for failure
3103 asl_unset(aslmsg a
, const char *key
)
3108 msg
= (asl_msg_t
*)a
;
3110 if (msg
== NULL
) return 0;
3111 if (key
== NULL
) return 0;
3113 for (i
= 0; i
< msg
->count
; i
++)
3115 if (msg
->key
[i
] == NULL
) continue;
3117 if (streq(msg
->key
[i
], key
))
3120 if (msg
->val
[i
] != NULL
) free(msg
->val
[i
]);
3122 for (j
= i
+ 1; j
< msg
->count
; j
++, i
++)
3124 msg
->key
[i
] = msg
->key
[j
];
3125 msg
->val
[i
] = msg
->val
[j
];
3126 if (msg
->op
!= NULL
) msg
->op
[i
] = msg
->op
[j
];
3131 if (msg
->count
== 0)
3139 if (msg
->op
!= NULL
) free(msg
->op
);
3144 msg
->key
= (char **)reallocf(msg
->key
, msg
->count
* sizeof(char *));
3145 if (msg
->key
== NULL
) return -1;
3147 msg
->val
= (char **)reallocf(msg
->val
, msg
->count
* sizeof(char *));
3148 if (msg
->val
== NULL
) return -1;
3150 if (msg
->op
!= NULL
)
3152 msg
->op
= (uint32_t *)reallocf(msg
->op
, msg
->count
* sizeof(uint32_t));
3153 if (msg
->op
== NULL
) return -1;
3165 * asl_search: Search for messages matching the criteria described
3166 * by the aslmsg. The caller should set the attributes to match using
3167 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
3168 * used for attributes set with asl_set().
3170 * returns: a set of messages that can be iterated over using aslresp_next(),
3171 * and the values can be retrieved using aslresp_get.
3174 asl_search(aslclient ac
, aslmsg a
)
3176 asl_search_result_t query
, *out
;
3177 asl_msg_t
*qlist
[1];
3182 if (a
== NULL
) return NULL
;
3185 status
= asl_store_open_read(NULL
, &store
);
3186 if (status
!= 0) return NULL
;
3187 if (store
== NULL
) return NULL
;
3193 memset(&query
, 0, sizeof(asl_search_result_t
));
3197 status
= asl_store_match(store
, &query
, &out
, &last_id
, 0, 0, 1);
3198 asl_store_close(store
);
3204 * aslresponse_next: Iterate over responses returned from asl_search()
3205 * a: a response returned from asl_search();
3206 * returns: The next log message (an aslmsg) or NULL on failure
3209 aslresponse_next(aslresponse r
)
3211 asl_search_result_t
*res
;
3214 res
= (asl_search_result_t
*)r
;
3215 if (res
== NULL
) return NULL
;
3217 if (res
->curr
>= res
->count
) return NULL
;
3218 m
= res
->msg
[res
->curr
];
3225 * aslresponse_free: Free a response returned from asl_search()
3226 * a: a response returned from asl_search()
3229 aslresponse_free(aslresponse r
)
3231 asl_search_result_t
*res
;
3234 res
= (asl_search_result_t
*)r
;
3235 if (res
== NULL
) return;
3237 for (i
= 0; i
< res
->count
; i
++) asl_free(res
->msg
[i
]);
3243 asl_syslog_faciliy_name_to_num(const char *name
)
3245 if (name
== NULL
) return -1;
3247 if (strcaseeq(name
, "auth")) return LOG_AUTH
;
3248 if (strcaseeq(name
, "authpriv")) return LOG_AUTHPRIV
;
3249 if (strcaseeq(name
, "cron")) return LOG_CRON
;
3250 if (strcaseeq(name
, "daemon")) return LOG_DAEMON
;
3251 if (strcaseeq(name
, "ftp")) return LOG_FTP
;
3252 if (strcaseeq(name
, "install")) return LOG_INSTALL
;
3253 if (strcaseeq(name
, "kern")) return LOG_KERN
;
3254 if (strcaseeq(name
, "lpr")) return LOG_LPR
;
3255 if (strcaseeq(name
, "mail")) return LOG_MAIL
;
3256 if (strcaseeq(name
, "netinfo")) return LOG_NETINFO
;
3257 if (strcaseeq(name
, "remoteauth")) return LOG_REMOTEAUTH
;
3258 if (strcaseeq(name
, "news")) return LOG_NEWS
;
3259 if (strcaseeq(name
, "security")) return LOG_AUTH
;
3260 if (strcaseeq(name
, "syslog")) return LOG_SYSLOG
;
3261 if (strcaseeq(name
, "user")) return LOG_USER
;
3262 if (strcaseeq(name
, "uucp")) return LOG_UUCP
;
3263 if (strcaseeq(name
, "local0")) return LOG_LOCAL0
;
3264 if (strcaseeq(name
, "local1")) return LOG_LOCAL1
;
3265 if (strcaseeq(name
, "local2")) return LOG_LOCAL2
;
3266 if (strcaseeq(name
, "local3")) return LOG_LOCAL3
;
3267 if (strcaseeq(name
, "local4")) return LOG_LOCAL4
;
3268 if (strcaseeq(name
, "local5")) return LOG_LOCAL5
;
3269 if (strcaseeq(name
, "local6")) return LOG_LOCAL6
;
3270 if (strcaseeq(name
, "local7")) return LOG_LOCAL7
;
3271 if (strcaseeq(name
, "launchd")) return LOG_LAUNCHD
;
3277 asl_syslog_faciliy_num_to_name(int n
)
3279 if (n
< 0) return NULL
;
3281 if (n
== LOG_AUTH
) return "auth";
3282 if (n
== LOG_AUTHPRIV
) return "authpriv";
3283 if (n
== LOG_CRON
) return "cron";
3284 if (n
== LOG_DAEMON
) return "daemon";
3285 if (n
== LOG_FTP
) return "ftp";
3286 if (n
== LOG_INSTALL
) return "install";
3287 if (n
== LOG_KERN
) return "kern";
3288 if (n
== LOG_LPR
) return "lpr";
3289 if (n
== LOG_MAIL
) return "mail";
3290 if (n
== LOG_NETINFO
) return "netinfo";
3291 if (n
== LOG_REMOTEAUTH
) return "remoteauth";
3292 if (n
== LOG_NEWS
) return "news";
3293 if (n
== LOG_AUTH
) return "security";
3294 if (n
== LOG_SYSLOG
) return "syslog";
3295 if (n
== LOG_USER
) return "user";
3296 if (n
== LOG_UUCP
) return "uucp";
3297 if (n
== LOG_LOCAL0
) return "local0";
3298 if (n
== LOG_LOCAL1
) return "local1";
3299 if (n
== LOG_LOCAL2
) return "local2";
3300 if (n
== LOG_LOCAL3
) return "local3";
3301 if (n
== LOG_LOCAL4
) return "local4";
3302 if (n
== LOG_LOCAL5
) return "local5";
3303 if (n
== LOG_LOCAL6
) return "local6";
3304 if (n
== LOG_LOCAL7
) return "local7";
3305 if (n
== LOG_LAUNCHD
) return "launchd";
3311 * utility for converting a time string into a time_t
3312 * we only deal with the following formats:
3313 * Canonical form YYYY.MM.DD hh:mm:ss UTC
3314 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
3315 * absolute form - # seconds since the epoch (e.g. 1095789191)
3316 * relative time - seconds before or after now (e.g. -300, +43200)
3317 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
3320 #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$"
3321 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
3322 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
3323 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
3325 #define SECONDS_PER_MINUTE 60
3326 #define SECONDS_PER_HOUR 3600
3327 #define SECONDS_PER_DAY 86400
3328 #define SECONDS_PER_WEEK 604800
3331 * We use the last letter in the month name to determine
3332 * the month number (0-11). There are two collisions:
3333 * Jan and Jun both end in n
3334 * Mar and Apr both end in r
3335 * In these cases we check the second letter.
3337 * The MTH_LAST array maps the last letter to a number.
3339 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};
3348 if (s
[2] > 90) v8
= s
[2] - 'a';
3349 else v8
= s
[2] - 'A';
3351 if ((v8
< 0) || (v8
> 25)) return -1;
3354 if (v8
< 0) return -1;
3357 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
3358 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
3363 asl_parse_time(const char *in
)
3365 int len
, y
, status
, rflags
;
3367 time_t tick
, delta
, factor
;
3369 static regex_t rex_canon
, rex_ctime
, rex_abs
, rex_rel
;
3370 static int init_canon
= 0;
3371 static int init_ctime
= 0;
3372 static int init_abs
= 0;
3373 static int init_rel
= 0;
3375 if (in
== NULL
) return -1;
3377 rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
3379 if (init_canon
== 0)
3381 memset(&rex_canon
, 0, sizeof(regex_t
));
3382 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
3383 if (status
!= 0) return -1;
3387 if (init_ctime
== 0)
3389 memset(&rex_ctime
, 0, sizeof(regex_t
));
3390 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
3391 if (status
!= 0) return -1;
3397 memset(&rex_abs
, 0, sizeof(regex_t
));
3398 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
3399 if (status
!= 0) return -1;
3405 memset(&rex_rel
, 0, sizeof(regex_t
));
3406 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
3407 if (status
!= 0) return -1;
3411 len
= strlen(in
) + 1;
3413 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
3416 * Absolute time (number of seconds since the epoch)
3419 if (str
== NULL
) return -1;
3421 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
3428 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
3431 * Reletive time (number of seconds before or after right now)
3434 if (str
== NULL
) return -1;
3438 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
3442 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
3445 factor
= SECONDS_PER_MINUTE
;
3447 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
3450 factor
= SECONDS_PER_HOUR
;
3452 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
3455 factor
= SECONDS_PER_DAY
;
3457 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
3460 factor
= SECONDS_PER_WEEK
;
3464 delta
= factor
* atol(str
);
3471 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
3473 memset(&t
, 0, sizeof(struct tm
));
3475 if (str
== NULL
) return -1;
3481 t
.tm_year
= atoi(x
) - 1900;
3487 t
.tm_mon
= atoi(x
) - 1;
3493 t
.tm_mday
= atoi(x
);
3496 for (x
= p
+ 1; *x
== ' '; x
++);
3499 t
.tm_hour
= atoi(x
);
3516 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
3518 /* We assume it's in the current year */
3519 memset(&t
, 0, sizeof(struct tm
));
3521 gmtime_r(&tick
, &t
);
3524 memset(&t
, 0, sizeof(struct tm
));
3526 if (str
== NULL
) return -1;
3529 t
.tm_mon
= _month_num(str
);
3530 if (t
.tm_mon
< 0) return -1;
3532 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
3535 t
.tm_mday
= atoi(x
);
3538 for (x
= p
+ 1; *x
== ' '; x
++);
3541 t
.tm_hour
= atoi(x
);
3562 #ifdef ASL_SYSLOG_COMPAT
3564 __private_extern__
void
3565 asl_syslog_syslog(int pri
, const char *fmt
, ...)
3570 if (fmt
== NULL
) return;
3572 m
= asl_new(ASL_TYPE_MSG
);
3575 asl_vlog(NULL
, m
, pri
, fmt
, ap
);
3581 __private_extern__
void
3582 asl_syslog_vsyslog(int pri
, const char *fmt
, va_list ap
)
3586 m
= asl_new(ASL_TYPE_MSG
);
3587 asl_vlog(NULL
, m
, pri
, fmt
, ap
);
3591 __private_extern__
void
3592 asl_syslog_openlog(const char *ident
, int flags
, int facility
)
3599 if (flags
& LOG_NDELAY
) opts
|= ASL_OPT_NO_DELAY
;
3600 if (flags
& LOG_PERROR
) opts
|= ASL_OPT_STDERR
;
3602 fname
= asl_syslog_faciliy_num_to_name(facility
);
3603 if (fname
== NULL
) fname
= "user";
3605 asl_global_client
= asl_open(ident
, fname
, opts
);
3608 __private_extern__
void
3609 asl_syslog_closelog()
3614 __private_extern__
int
3615 asl_syslog_setlogmask(int p
)
3617 return asl_set_filter(p
);
3620 #endif ASL_SYSLOG_COMPAT
3622 #endif /* BUILDING_VARIANT */