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