]> git.saurik.com Git - apple/syslog.git/blame - libsystem_asl.tproj/src/asl.c
syslog-385.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl.c
CommitLineData
81582353 1/*
5222c21d 2 * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
81582353
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
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.
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,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
81582353
A
24#include <string.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <stdarg.h>
31#include <syslog.h>
32#include <errno.h>
33#include <limits.h>
34#include <time.h>
f3df4c03 35#include <sys/stat.h>
81582353
A
36#include <sys/time.h>
37#include <sys/fcntl.h>
f3df4c03
A
38#include <sys/param.h>
39#include <sys/fileport.h>
81582353
A
40#include <crt_externs.h>
41#include <asl.h>
42#include <regex.h>
43#include <notify.h>
44#include <mach/mach.h>
45#include <mach/std_types.h>
46#include <mach/mig.h>
47#include <mach/mach_types.h>
48#include <sys/types.h>
49#include <servers/bootstrap.h>
50#include <bootstrap_priv.h>
51#include <pthread.h>
52#include <dispatch/dispatch.h>
53#include <libkern/OSAtomic.h>
f3df4c03 54#include <os/activity.h>
af7d442c 55#include <os/log.h>
5222c21d 56#include <os/log_private.h>
81582353 57#include <asl_ipc.h>
f3df4c03
A
58#include <asl_client.h>
59#include <asl_core.h>
60#include <asl_msg.h>
61#include <asl_msg_list.h>
62#include <asl_store.h>
63#include <asl_private.h>
81582353
A
64
65#define forever for(;;)
66
67#define FETCH_BATCH 256
68
5222c21d
A
69#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
70#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
81582353
A
71
72/*
73 * Clients get a max of 36000 messages per hour.
74 * Their quota gets refilled at a rate of 10 messages per second.
75 */
76#define QUOTA_MPH 36000
77#define QUOTA_MPS 10
78#define QUOTA_MSG_INTERVAL 60
f3df4c03
A
79#define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
80#define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
81582353 81#define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
5222c21d
A
82#define QUOTA_LEVEL ASL_LEVEL_CRIT
83#define QUOTA_LEVEL_STR ASL_STRING_CRIT
84
85/*
86 * Limit the size of messages sent to syslogd.
87 */
88#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
89
af7d442c
A
90static const os_log_type_t shim_asl_to_log_type[8] = {
91 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_EMERG
92 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ALERT
93 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_CRIT
94 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ERR
95 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_WARNING
96 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_NOTICE
97 OS_LOG_TYPE_INFO, // ASL_LEVEL_INFO
98 OS_LOG_TYPE_DEBUG // ASL_LEVEL_DEBUG
5222c21d
A
99};
100
81582353 101/* forward */
f3df4c03 102static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
af7d442c 103static ASL_STATUS _asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring, bool shimmed);
81582353
A
104__private_extern__ asl_client_t *_asl_open_default();
105
81582353
A
106/* notify SPI */
107uint32_t notify_register_plain(const char *name, int *out_token);
108
f3df4c03
A
109/* fork handling in asl_fd.c */
110extern void _asl_redirect_fork_child(void);
81582353 111
86a8bcf5
A
112#if TARGET_OS_OSX
113extern void _asl_mt_shim_fork_child(void);
114extern void _asl_mt_shim_send_message(asl_msg_t *msg);
115#endif
116
81582353
A
117typedef struct
118{
119 int fd;
120 asl_msg_t *msg;
121 dispatch_semaphore_t sem;
122} asl_aux_context_t;
123
124typedef struct
125{
126 int notify_count;
127 int rc_change_token;
128 int notify_token;
129 int master_token;
130 uint64_t proc_filter;
131 uint64_t master_filter;
132 time_t last_send;
133 time_t last_oq_msg;
134 uint32_t quota;
30cde84f 135 dispatch_once_t port_lookup_once;
81582353
A
136 mach_port_t server_port;
137 char *sender;
138 pthread_mutex_t lock;
139 int aux_count;
140 asl_aux_context_t **aux_ctx;
141 asl_client_t *asl;
142} _asl_global_t;
143
30cde84f 144__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
81582353 145
f3df4c03 146static const char *level_to_number_string[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
81582353
A
147
148#define ASL_SERVICE_NAME "com.apple.system.logger"
149
150/*
151 * Called from the child process inside fork() to clean up
152 * inherited state from the parent process.
153 *
154 * NB. A lock isn't required, since we're single threaded in this call.
155 */
156void
157_asl_fork_child()
158{
159 _asl_global.notify_count = 0;
160 _asl_global.rc_change_token = -1;
161 _asl_global.master_token = -1;
162 _asl_global.notify_token = -1;
163 _asl_global.quota = 0;
164 _asl_global.last_send = 0;
165 _asl_global.last_oq_msg = 0;
166
30cde84f 167 _asl_global.port_lookup_once = 0;
81582353
A
168 _asl_global.server_port = MACH_PORT_NULL;
169
170 pthread_mutex_init(&(_asl_global.lock), NULL);
f3df4c03
A
171
172 _asl_redirect_fork_child();
86a8bcf5
A
173#if TARGET_OS_OSX
174 _asl_mt_shim_fork_child();
175#endif
81582353
A
176}
177
178/*
179 * asl_remote_notify_name: returns the notification key for remote-control filter
180 * changes for this process.
181 */
182char *
183asl_remote_notify_name()
184{
185 pid_t pid = getpid();
186 uid_t euid = geteuid();
187 char *str = NULL;
188
189 if (euid == 0) asprintf(&str, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
190 else asprintf(&str, "user.uid.%d.syslog.%d", euid, pid);
191
192 return str;
193}
194
f3df4c03 195static ASL_STATUS
81582353
A
196_asl_notify_open(int do_lock)
197{
198 char *notify_name;
199 uint32_t status;
200
201 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
202
203 _asl_global.notify_count++;
204
205 if (_asl_global.notify_token != -1)
206 {
207 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 208 return ASL_STATUS_OK;
81582353
A
209 }
210
211 if (_asl_global.rc_change_token == -1)
212 {
213 status = notify_register_check(NOTIFY_RC, &_asl_global.rc_change_token);
214 if (status != NOTIFY_STATUS_OK) _asl_global.rc_change_token = -1;
215 }
216
217 if (_asl_global.master_token == -1)
218 {
219 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
220 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
221 }
222
223 notify_name = asl_remote_notify_name();
224 if (notify_name != NULL)
225 {
226 status = notify_register_plain(notify_name, &_asl_global.notify_token);
227 free(notify_name);
228 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
229 }
230
231 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
232
f3df4c03
A
233 if (_asl_global.notify_token == -1) return ASL_STATUS_FAILED;
234 return ASL_STATUS_OK;
81582353
A
235}
236
f3df4c03 237#ifdef UNDEF
81582353
A
238static void
239_asl_notify_close()
240{
241 pthread_mutex_lock(&_asl_global.lock);
242
243 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
244
245 if (_asl_global.notify_count > 0)
246 {
247 pthread_mutex_unlock(&_asl_global.lock);
248 return;
249 }
250
251 if (_asl_global.rc_change_token >= 0) notify_cancel(_asl_global.rc_change_token);
252 _asl_global.rc_change_token = -1;
253
254 if (_asl_global.master_token >= 0) notify_cancel(_asl_global.master_token);
255 _asl_global.master_token = -1;
256
257 if (_asl_global.notify_token >= 0) notify_cancel(_asl_global.notify_token);
258 _asl_global.notify_token = -1;
259
260 pthread_mutex_unlock(&_asl_global.lock);
261}
f3df4c03 262#endif
81582353
A
263
264static void
30cde84f 265_asl_global_init()
81582353 266{
30cde84f
A
267 dispatch_once(&_asl_global.port_lookup_once, ^{
268 char *str = getenv("ASL_DISABLE");
269 if ((str == NULL) || strcmp(str, "1"))
270 {
51023e60
A
271 kern_return_t kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &_asl_global.server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
272 if (kstatus != KERN_SUCCESS)
273 {
274 _asl_global.server_port = MACH_PORT_NULL;
275 }
30cde84f
A
276 }
277 });
278}
279
280mach_port_t
281asl_core_get_service_port(__unused int reset)
282{
283 _asl_global_init();
284 return _asl_global.server_port;
81582353
A
285}
286
f3df4c03
A
287#pragma mark -
288#pragma mark asl_client
81582353 289
f3df4c03 290asl_object_t
81582353
A
291asl_open(const char *ident, const char *facility, uint32_t opts)
292{
f3df4c03
A
293 asl_client_t *asl = asl_client_open(ident, facility, opts);
294 if (asl == NULL) return NULL;
81582353 295
f3df4c03 296 if (!(opts & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
81582353 297
f3df4c03 298 return (asl_object_t)asl;
81582353
A
299}
300
f3df4c03 301asl_object_t
81582353
A
302asl_open_from_file(int fd, const char *ident, const char *facility)
303{
f3df4c03 304 return (asl_object_t)asl_client_open_from_file(fd, ident, facility);
81582353
A
305}
306
307void
f3df4c03 308asl_close(asl_object_t obj)
81582353 309{
f3df4c03 310 asl_release(obj);
81582353
A
311}
312
313__private_extern__ asl_client_t *
314_asl_open_default()
315{
316 static dispatch_once_t once;
317
318 dispatch_once(&once, ^{
319 /*
320 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
321 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
322 * which locks _asl_global.lock.
323 */
f3df4c03 324 _asl_global.asl = (asl_client_t *)asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
81582353
A
325
326 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
327 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
328
329 /* Now call _asl_notify_open(0) to finish the work */
330 _asl_notify_open(0);
331 });
332
333 return _asl_global.asl;
334}
335
336/*
337 * asl_add_file: write log messages to the given file descriptor
338 * Log messages will be written to this file as well as to the server.
339 */
340int
f3df4c03 341asl_add_output_file(asl_object_t client, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding)
81582353 342{
f3df4c03 343 int status, use_global_lock = 0;
81582353
A
344 asl_client_t *asl;
345
f3df4c03
A
346 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
347
348 asl = (asl_client_t *)client;
81582353
A
349 if (asl == NULL)
350 {
351 asl = _asl_open_default();
352 if (asl == NULL) return -1;
353 pthread_mutex_lock(&_asl_global.lock);
354 use_global_lock = 1;
355 }
356
f3df4c03 357 status = asl_client_add_output_file(asl, fd, mfmt, tfmt, filter, text_encoding);
81582353
A
358
359 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 360 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
361}
362
f3df4c03 363/* returns previous filter value or -1 on error */
81582353 364int
f3df4c03 365asl_set_output_file_filter(asl_object_t client, int fd, int filter)
81582353 366{
f3df4c03
A
367 uint32_t last;
368 int use_global_lock = 0;
81582353
A
369 asl_client_t *asl;
370
f3df4c03
A
371 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
372
373 asl = (asl_client_t *)client;
81582353
A
374 if (asl == NULL)
375 {
376 asl = _asl_open_default();
377 if (asl == NULL) return -1;
378 pthread_mutex_lock(&_asl_global.lock);
379 use_global_lock = 1;
380 }
381
f3df4c03 382 last = asl_client_set_output_file_filter(asl, fd, filter);
81582353
A
383
384 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
385 return last;
386}
387
388/* SPI - Deprecated */
389int
f3df4c03 390asl_add_output(asl_object_t client, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding)
81582353 391{
f3df4c03 392 return asl_add_output_file(client, fd, mfmt, tfmt, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), text_encoding);
81582353
A
393}
394
f3df4c03 395/* SPI - Deprecated */
81582353 396int
f3df4c03 397asl_add_log_file(asl_object_t client, int fd)
81582353 398{
f3df4c03 399 return asl_add_output_file(client, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE);
81582353
A
400}
401
402/*
403 * asl_remove_output: stop writing log messages to the given file descriptor
404 */
405int
f3df4c03 406asl_remove_output_file(asl_object_t client, int fd)
81582353 407{
f3df4c03 408 int status, use_global_lock = 0;
81582353
A
409 asl_client_t *asl;
410
f3df4c03
A
411 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
412
413 asl = (asl_client_t *)client;
81582353
A
414 if (asl == NULL)
415 {
416 asl = _asl_open_default();
417 if (asl == NULL) return -1;
418 pthread_mutex_lock(&_asl_global.lock);
419 use_global_lock = 1;
420 }
421
f3df4c03 422 status = asl_client_remove_output_file(asl, fd);
81582353
A
423
424 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 425 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
426}
427
428int
f3df4c03 429asl_remove_output(asl_object_t client, int fd)
81582353 430{
f3df4c03 431 return asl_remove_output_file(client, fd);
81582353
A
432}
433
434int
f3df4c03 435asl_remove_log_file(asl_object_t client, int fd)
81582353 436{
f3df4c03 437 return asl_remove_output_file(client, fd);
81582353
A
438}
439
f3df4c03 440/* returns previous filter value or -1 on error */
81582353 441int
f3df4c03 442asl_set_filter(asl_object_t client, int f)
81582353 443{
f3df4c03 444 int last, use_global_lock = 0;
81582353
A
445 asl_client_t *asl;
446
f3df4c03
A
447 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
448
449 asl = (asl_client_t *)client;
81582353
A
450 if (asl == NULL)
451 {
452 asl = _asl_open_default();
453 if (asl == NULL) return -1;
454 pthread_mutex_lock(&_asl_global.lock);
455 use_global_lock = 1;
456 }
457
f3df4c03 458 last = asl_client_set_filter(asl, f);
81582353
A
459
460 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
461 return last;
462}
463
f3df4c03
A
464
465#pragma mark -
466#pragma mark message sending
467
81582353
A
468/*
469 * Evaluate client / message / level to determine what to do with a message.
5222c21d
A
470 * Checks filters, tunneling, and log files.
471 * Returns the bits below, ORed with the message level.
81582353 472 *
5222c21d
A
473 * EVAL_SEND_ASL - send this message to syslogd
474 * EVAL_SEND_TRACE - log this message with Activity Tracing
475 * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file)
476 * EVAL_TEXT_FILE - write this message to a text file / stderr
477 * EVAL_TUNNEL - tunneling enabled when sending to syslogd
81582353
A
478 */
479uint32_t
f3df4c03 480_asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
81582353 481{
f3df4c03
A
482 asl_client_t *asl;
483 asl_msg_t *msg = (asl_msg_t *)m;
81582353 484 uint32_t level, lmask, filter, status, tunnel;
f3df4c03 485 int check;
81582353
A
486 uint64_t v64;
487 const char *val;
5222c21d 488 uint32_t eval;
81582353 489
f3df4c03
A
490 level = ASL_LEVEL_DEBUG;
491 if (slevel >= 0) level = slevel;
5222c21d 492
f3df4c03
A
493 val = NULL;
494 if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
5222c21d 495
f3df4c03
A
496 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
497 else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
498
499 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
500 {
501 /* sending to something other than a client */
5222c21d 502 return EVAL_ACTIVE | EVAL_SEND_ASL | level;
f3df4c03
A
503 }
504
505 asl = (asl_client_t *)client;
5222c21d
A
506 if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
507
508 if (asl == NULL) asl = _asl_open_default();
81582353
A
509 if (asl == NULL)
510 {
5222c21d
A
511 eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
512 eval &= ~EVAL_SEND_ASL;
513 return eval;
81582353
A
514 }
515
5222c21d 516 eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
81582353
A
517
518 filter = asl->filter & 0xff;
519 tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
5222c21d
A
520 if (tunnel != 0) eval |= EVAL_TUNNEL;
521
5222c21d 522 if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
81582353
A
523 {
524 pthread_mutex_lock(&_asl_global.lock);
525
526 if (_asl_global.rc_change_token >= 0)
527 {
528 /* initialize or re-check process-specific and master filters */
529 check = 0;
530 status = notify_check(_asl_global.rc_change_token, &check);
531 if ((status == NOTIFY_STATUS_OK) && (check != 0))
532 {
533 if (_asl_global.master_token >= 0)
534 {
535 v64 = 0;
536 status = notify_get_state(_asl_global.master_token, &v64);
537 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
538 }
539
540 if (_asl_global.notify_token >= 0)
541 {
542 v64 = 0;
543 status = notify_get_state(_asl_global.notify_token, &v64);
544 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
545 }
546 }
547 }
548
5222c21d 549 if (_asl_global.master_filter & EVAL_ACTIVE)
81582353 550 {
5222c21d
A
551 /* clear bits and set according to master */
552 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
553 eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
554 eval |= EVAL_TUNNEL;
81582353 555
5222c21d 556 if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
81582353 557 }
81582353 558
5222c21d
A
559 if (_asl_global.proc_filter & EVAL_ACTIVE)
560 {
561 /* clear bits and set according to proc */
562 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
563 eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
564 eval |= EVAL_TUNNEL;
81582353 565
5222c21d
A
566 if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
567 }
81582353 568
5222c21d 569 pthread_mutex_unlock(&_asl_global.lock);
81582353
A
570 }
571
5222c21d
A
572 lmask = ASL_FILTER_MASK(level);
573 if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
574 if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
81582353 575
af7d442c
A
576 /* don't send MessageTracer messages to Activity Tracing */
577 val = NULL;
86a8bcf5
A
578 if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL))
579 {
580 eval &= ~EVAL_SEND_TRACE;
581 eval |= EVAL_MT_SHIM;
582 }
af7d442c
A
583
584 /* don't send PowerManagement messages to Activity Tracing */
585 val = NULL;
586 if ((asl_msg_lookup(msg, ASL_KEY_POWERMANAGEMENT, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
587
588 /* don't send control messages to Activity Tracing */
589 val = NULL;
590 if ((asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
591
af7d442c
A
592 /* don't send CFLog messages to Activity Tracing */
593 val = NULL;
594 if ((asl_msg_lookup(msg, ASL_KEY_CFLOG_LOCAL_TIME, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
595
797dbbb8
A
596 val = NULL;
597 if (((asl_msg_lookup(msg, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)) ||
598 ((asl_msg_lookup(asl->kvdict, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)))
599 {
600 /* don't send lastlog/utmp messages to Activity Tracing */
601 if (!strcmp(val, FACILITY_LASTLOG) || !strcmp(val, FACILITY_UTMPX)) eval &= ~EVAL_SEND_TRACE;
602
603 /* don't send LOG_INSTALL messages to Activity Tracing */
604 if (!strcmp(val, asl_syslog_faciliy_num_to_name(LOG_INSTALL))) eval &= ~EVAL_SEND_TRACE;
605 }
606
5222c21d 607 return eval;
81582353
A
608}
609
af7d442c
A
610/*
611 * _asl_lib_vlog_text
612 * Internal routine used by asl_vlog.
613 * msg: an asl messsage
614 * eval: log level and send flags for the message
615 * format: A formating string
616 * ap: va_list for the format
617 * returns 0 for success, non-zero for failure
618 */
619
620__private_extern__ ASL_STATUS
621_asl_lib_vlog_text(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
622{
623 int saved_errno = errno;
624 int status;
625 char *str, *fmt, estr[NL_TEXTMAX];
626 uint32_t i, len, elen, expand;
627
628 if (format == NULL) return ASL_STATUS_INVALID_ARG;
629
630 /* insert strerror for %m */
631 len = 0;
632 elen = 0;
633
634 expand = 0;
635 for (i = 0; format[i] != '\0'; i++)
636 {
637 if (format[i] == '%')
638 {
639 if (format[i+1] == '\0') len++;
640 else if (format[i+1] == 'm')
641 {
642 expand = 1;
643 strerror_r(saved_errno, estr, sizeof(estr));
644 elen = strlen(estr);
645 len += elen;
646 i++;
647 }
648 else
649 {
650 len += 2;
651 i++;
652 }
653 }
654 else len++;
655 }
656
657 fmt = (char *)format;
658
659 if (expand != 0)
660 {
661 fmt = malloc(len + 1);
662 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
663
664 len = 0;
665
666 for (i = 0; format[i] != '\0'; i++)
667 {
668 if (format[i] == '%')
669 {
670 if (format[i+1] == '\0')
671 {
672 }
673 else if ((format[i+1] == 'm') && (elen != 0))
674 {
675 memcpy(fmt+len, estr, elen);
676 len += elen;
677 i++;
678 }
679 else
680 {
681 fmt[len++] = format[i++];
682 fmt[len++] = format[i];
683 }
684 }
685 else fmt[len++] = format[i];
686 }
687
688 fmt[len] = '\0';
689 }
690
691 str = NULL;
692 vasprintf(&str, fmt, ap);
693 if (expand != 0) free(fmt);
694
695 if (str == NULL) return ASL_STATUS_NO_MEMORY;
696
697 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, str, true);
698 free(str);
699
700 return status;
701}
702
81582353
A
703/*
704 * _asl_lib_vlog
705 * Internal routine used by asl_vlog.
f3df4c03 706 * msg: an asl messsage
81582353
A
707 * eval: log level and send flags for the message
708 * format: A formating string
709 * ap: va_list for the format
710 * returns 0 for success, non-zero for failure
711 */
5222c21d 712__private_extern__ ASL_STATUS
f3df4c03 713_asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
81582353
A
714{
715 int saved_errno = errno;
716 int status;
717 char *str, *fmt, estr[NL_TEXTMAX];
718 uint32_t i, len, elen, expand;
81582353 719
f3df4c03 720 if (format == NULL) return ASL_STATUS_INVALID_ARG;
81582353
A
721
722 /* insert strerror for %m */
723 len = 0;
724 elen = 0;
725
726 expand = 0;
727 for (i = 0; format[i] != '\0'; i++)
728 {
729 if (format[i] == '%')
730 {
731 if (format[i+1] == '\0') len++;
732 else if (format[i+1] == 'm')
733 {
734 expand = 1;
735 strerror_r(saved_errno, estr, sizeof(estr));
736 elen = strlen(estr);
737 len += elen;
738 i++;
739 }
740 else
741 {
742 len += 2;
743 i++;
744 }
745 }
746 else len++;
747 }
748
749 fmt = (char *)format;
750
751 if (expand != 0)
752 {
753 fmt = malloc(len + 1);
5222c21d 754 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
81582353
A
755
756 len = 0;
757
758 for (i = 0; format[i] != '\0'; i++)
759 {
760 if (format[i] == '%')
761 {
762 if (format[i+1] == '\0')
763 {
764 }
765 else if ((format[i+1] == 'm') && (elen != 0))
766 {
767 memcpy(fmt+len, estr, elen);
768 len += elen;
769 i++;
770 }
771 else
772 {
773 fmt[len++] = format[i++];
774 fmt[len++] = format[i];
775 }
776 }
777 else fmt[len++] = format[i];
778 }
779
780 fmt[len] = '\0';
781 }
782
783 str = NULL;
784 vasprintf(&str, fmt, ap);
785 if (expand != 0) free(fmt);
786
f3df4c03 787 if (str == NULL) return ASL_STATUS_NO_MEMORY;
81582353 788
f3df4c03 789 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, str);
81582353
A
790 free(str);
791
792 return status;
793}
794
795/*
796 * asl_vlog
797 * Similar to asl_log, but take a va_list instead of a list of arguments.
f3df4c03 798 * msg: an asl message
81582353
A
799 * level: the log level of the associated message
800 * format: A formating string
801 * ap: va_list for the format
802 * returns 0 for success, non-zero for failure
803 */
804int
f3df4c03 805asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
81582353 806{
5222c21d 807 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 808 uint32_t eval = _asl_evaluate_send(client, msg, level);
af7d442c 809 void *addr = __builtin_return_address(0);
81582353 810
af7d442c 811 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
5222c21d
A
812 {
813 va_list ap_copy;
814 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
815 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
af7d442c 816 os_log_type_t type = shim_asl_to_log_type[level];
5222c21d
A
817
818 va_copy(ap_copy, ap);
af7d442c 819 os_log_with_args(OS_LOG_DEFAULT, type, format, ap_copy, addr);
5222c21d 820 va_end(ap_copy);
5222c21d 821
af7d442c
A
822 if (eval & EVAL_TEXT_FILE)
823 {
824 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
825 }
826 }
827 else if (eval & EVAL_ASL)
5222c21d 828 {
af7d442c 829 status = _asl_lib_vlog(client, eval, msg, format, ap);
5222c21d
A
830 }
831
f3df4c03 832 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
833}
834
835/*
836 * _asl_lib_log
5222c21d 837 * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
81582353 838 * forwards the call to _asl_lib_vlog.
f3df4c03 839 * msg: an asl message
81582353
A
840 * eval: log level and send flags for the message
841 * format: A formating string
842 * ... args for format
843 * returns 0 for success, non-zero for failure
844 */
845int
f3df4c03 846_asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
81582353 847{
5222c21d 848 int status = 0;
81582353 849
5222c21d
A
850 if (eval & EVAL_ASL)
851 {
852 va_list ap;
853
854 va_start(ap, format);
855 status = _asl_lib_vlog(client, eval, msg, format, ap);
856 va_end(ap);
857 }
81582353
A
858
859 return status;
860}
861
862/*
863 * asl_log
864 * Processes an ASL log message.
f3df4c03 865 * msg: an asl message
81582353
A
866 * level: the log level of the associated message
867 * format: A formating string
868 * ... args for format
869 * returns 0 for success, non-zero for failure
870 */
871int
f3df4c03 872asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
81582353 873{
5222c21d 874 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 875 uint32_t eval = _asl_evaluate_send(client, msg, level);
af7d442c 876 void *addr = __builtin_return_address(0);
81582353 877
af7d442c 878 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
5222c21d
A
879 {
880 va_list ap;
881 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
882 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
af7d442c 883 os_log_type_t type = shim_asl_to_log_type[level];
5222c21d
A
884
885 va_start(ap, format);
af7d442c 886 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
5222c21d 887 va_end(ap);
5222c21d 888
af7d442c
A
889 if (eval & EVAL_TEXT_FILE)
890 {
891 va_list ap;
892 va_start(ap, format);
893 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
894 va_end(ap);
895 }
896 }
897 else if (eval & EVAL_ASL)
5222c21d
A
898 {
899 va_list ap;
5222c21d 900 va_start(ap, format);
af7d442c 901 status = _asl_lib_vlog(client, eval, msg, format, ap);
5222c21d 902 va_end(ap);
5222c21d 903 }
81582353 904
f3df4c03 905 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
906}
907
f3df4c03
A
908/*
909 * asl_log_message
910 * Like asl_log, supplies NULL client and msg.
911 * level: the log level of the associated message
912 * format: A formating string
913 * ... args for format
914 * returns 0 for success, non-zero for failure
915 */
916int
917asl_log_message(int level, const char *format, ...)
918{
5222c21d 919 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 920 uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
af7d442c 921 void *addr = __builtin_return_address(0);
f3df4c03 922
af7d442c 923 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
5222c21d
A
924 {
925 va_list ap;
926 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
927 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
af7d442c 928 os_log_type_t type = shim_asl_to_log_type[level];
5222c21d
A
929
930 va_start(ap, format);
af7d442c 931 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
5222c21d 932 va_end(ap);
5222c21d 933
af7d442c
A
934 if (eval & EVAL_TEXT_FILE)
935 {
936 va_list ap;
937 va_start(ap, format);
938 status = _asl_lib_vlog_text(NULL, eval, NULL, format, ap);
939 va_end(ap);
940 }
941 }
942 else if (eval & EVAL_ASL)
5222c21d
A
943 {
944 va_list ap;
5222c21d 945 va_start(ap, format);
af7d442c 946 status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
5222c21d 947 va_end(ap);
5222c21d 948 }
f3df4c03
A
949
950 return (status == ASL_STATUS_OK) ? 0 : -1;
951}
81582353
A
952
953/*
954 * asl_get_filter: gets the values for the local, master, and remote filters,
955 * and indicates which one is active.
956 */
957int
f3df4c03 958asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active)
81582353
A
959{
960 asl_client_t *asl, *asl_default;
961 int l, m, r, x;
962 int status, check;
963 uint64_t v64;
964
f3df4c03
A
965 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
966
81582353
A
967 l = 0;
968 m = 0;
969 r = 0;
970 x = 0;
971
972 asl_default = _asl_open_default();
973
f3df4c03 974 asl = (asl_client_t *)client;
81582353 975 if (asl == NULL) asl = asl_default;
5222c21d 976 if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
81582353
A
977
978 if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
979 {
980 pthread_mutex_lock(&_asl_global.lock);
981
982 if (_asl_global.rc_change_token >= 0)
983 {
984 /* initialize or re-check process-specific and master filters */
985 check = 0;
986 status = notify_check(_asl_global.rc_change_token, &check);
987 if ((status == NOTIFY_STATUS_OK) && (check != 0))
988 {
989 if (_asl_global.master_token >= 0)
990 {
991 v64 = 0;
992 status = notify_get_state(_asl_global.master_token, &v64);
993 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
994 }
995
996 if (_asl_global.notify_token >= 0)
997 {
998 v64 = 0;
999 status = notify_get_state(_asl_global.notify_token, &v64);
1000 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
1001 }
1002 }
1003 }
1004
1005 m = _asl_global.master_filter;
1006 if (m != 0) x = 1;
1007
1008 r = _asl_global.proc_filter;
1009 if (r != 0) x = 2;
1010
1011 pthread_mutex_unlock(&_asl_global.lock);
1012 }
1013
1014 if (local != NULL) *local = l;
1015 if (master != NULL) *master = m;
1016 if (remote != NULL) *remote = r;
1017 if (active != NULL) *active = x;
1018
1019 return 0;
1020}
1021
5222c21d
A
1022/* SPI for SHIM control */
1023uint32_t
1024asl_set_local_control(asl_object_t client, uint32_t filter)
1025{
1026 asl_client_t *asl = (asl_client_t *)client;
1027 if (asl == NULL)
1028 {
1029 asl = _asl_open_default();
1030 if (asl == NULL) return UINT32_MAX;
1031 }
1032 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
1033
1034 return asl_client_set_control(asl, filter);
1035}
1036
1037uint32_t
1038asl_get_local_control(asl_object_t client)
1039{
1040 asl_client_t *asl = (asl_client_t *)client;
1041 if (asl == NULL)
1042 {
1043 asl = _asl_open_default();
1044 if (asl == NULL) return UINT32_MAX;
1045 }
1046 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
1047
1048 return asl_client_get_control(asl);
1049}
1050
f3df4c03 1051/*
5222c21d 1052 * Sets PID and OSActivityID values in a new message.
f3df4c03
A
1053 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
1054 */
1055asl_msg_t *
1056asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
81582353 1057{
81582353 1058 char aux_val[64];
81582353 1059 asl_msg_t *aux;
f3df4c03 1060 int status;
15d86b03 1061 os_activity_id_t osaid;
81582353 1062
81582353 1063 aux = asl_msg_new(ASL_TYPE_MSG);
f3df4c03 1064 if (aux == NULL) return NULL;
81582353 1065
f3df4c03
A
1066 /* Level */
1067 if (level <= 7) asl_msg_set_key_val(aux, ASL_KEY_LEVEL, level_to_number_string[level]);
81582353 1068
f3df4c03
A
1069 /* Time and TimeNanoSec */
1070 if (tv != NULL)
81582353 1071 {
5222c21d 1072 snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
81582353 1073 asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
f3df4c03
A
1074
1075 snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
81582353
A
1076 asl_msg_set_key_val(aux, ASL_KEY_TIME_NSEC, aux_val);
1077 }
81582353 1078
f3df4c03
A
1079 /* Message */
1080 if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
1081
f3df4c03 1082 /* PID */
81582353
A
1083 snprintf(aux_val, sizeof(aux_val), "%u", getpid());
1084 asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
1085
f3df4c03 1086 /* OSActivityID */
15d86b03
A
1087 osaid = os_activity_get_identifier(OS_ACTIVITY_CURRENT, NULL);
1088 if (osaid)
81582353 1089 {
15d86b03 1090 snprintf(aux_val, sizeof(aux_val), "0x%016llx", osaid);
f3df4c03
A
1091 asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val);
1092 }
1093
1094 /* Sender */
5222c21d 1095 if ((sstr == NULL) && (asl != NULL))
f3df4c03
A
1096 {
1097 /* See if the client has a value for ASL_KEY_SENDER */
1098 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
1099 if ((status != 0) || (sstr == NULL))
81582353 1100 {
f3df4c03
A
1101 sstr = NULL;
1102
1103 /* See if the global cache has a value for ASL_KEY_SENDER */
81582353
A
1104 if (_asl_global.sender == NULL)
1105 {
f3df4c03
A
1106 /* Get the process name with _NSGetArgv */
1107 char *name = *(*_NSGetArgv());
81582353
A
1108 if (name != NULL)
1109 {
f3df4c03 1110 char *x = strrchr(name, '/');
81582353
A
1111 if (x != NULL) x++;
1112 else x = name;
1113
f3df4c03 1114 /* Set the cache value */
81582353
A
1115 pthread_mutex_lock(&_asl_global.lock);
1116 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
1117 pthread_mutex_unlock(&_asl_global.lock);
1118 }
1119 }
1120
1121 if (_asl_global.sender != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, _asl_global.sender);
1122 else asl_msg_set_key_val(aux, ASL_KEY_SENDER, "Unknown");
1123 }
1124 }
1125
f3df4c03
A
1126 if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
1127
1128 /* Facility */
5222c21d 1129 if ((fstr == NULL) && (asl != NULL))
81582353 1130 {
f3df4c03
A
1131 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
1132 if (status != 0) fstr = NULL;
81582353
A
1133 }
1134
f3df4c03
A
1135 if (fstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_FACILITY, fstr);
1136
1137 return aux;
1138}
1139
1140#ifdef NOTDEF
1141/*
1142 * Possibly useful someday...
1143 */
1144asl_msg_t *
1145asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
1146{
1147 uint32_t i, len, level, outstatus;
1148 const char *val, *sstr, *fstr;
1149 struct timeval tval = {0, 0};
1150 int status;
1151 asl_msg_t *out;
1152
1153 if (asl == NULL)
1154 {
1155 asl = _asl_open_default();
1156 if (asl == NULL) return NULL;
1157 }
1158
1159 status = gettimeofday(&tval, NULL);
1160 if (status != 0)
1161 {
1162 time_t tick = time(NULL);
1163 tval.tv_sec = tick;
1164 tval.tv_usec = 0;
1165 }
1166
1167 val = NULL;
1168 status = asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL);
1169 if (status != 0) val = NULL;
1170
1171 level = ASL_LEVEL_DEBUG;
1172 if (val != NULL) level = atoi(val);
1173 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1174
1175 sstr = NULL;
1176 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1177 if (status != 0) sstr = NULL;
1178
1179 fstr = NULL;
1180 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1181 if (status != 0) fstr = NULL;
1182
1183 out = asl_base_msg(asl, level, &tval, sstr, fstr, NULL);
1184 out = asl_msg_merge(out, msg);
1185
1186 return out;
1187}
1188#endif
1189
5222c21d
A
1190static void
1191_asl_set_option(asl_msg_t *msg, const char *opt)
1192{
1193 const char *val = NULL;
1194 uint32_t status;
1195
1196 if (msg == NULL) return;
1197 if (opt == NULL) return;
1198
1199 status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
1200 if ((status != 0) || (val == NULL))
1201 {
1202 asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
1203 }
1204 else
1205 {
1206 char *option = NULL;
1207 asprintf(&option, "%s %s", opt, val);
1208 asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
1209 free(option);
1210 }
1211}
1212
af7d442c
A
1213static ASL_STATUS
1214_asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr, bool shimmed)
1215{
1216 int status;
1217 uint32_t level, lmask;
1218 asl_msg_t *release_sendmsg = NULL;
1219
1220 if (asl == NULL) {
1221 if (obj == NULL) {
1222 asl = _asl_open_default();
1223 if (asl == NULL) return ASL_STATUS_FAILED;
1224 } else {
1225 uint32_t objtype = asl_get_type(obj);
1226 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
1227 }
1228 }
1229
1230 level = eval & EVAL_LEVEL_MASK;
1231 if (level > 7) level = 7;
1232 lmask = ASL_FILTER_MASK(level);
1233
1234 if (sendmsg == NULL) {
1235 struct timeval tval = {0, 0};
1236 const char *sstr, *fstr;
1237
1238 status = gettimeofday(&tval, NULL);
1239 if (status != 0) {
1240 time_t tick = time(NULL);
1241 tval.tv_sec = tick;
1242 tval.tv_usec = 0;
1243 }
1244
1245 sstr = NULL;
1246 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1247 if (status != 0) {
1248 sstr = NULL;
1249 }
1250
1251 fstr = NULL;
1252 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1253 if (status != 0) {
1254 fstr = NULL;
1255 }
1256 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1257 if (sendmsg == NULL) {
1258 return ASL_STATUS_FAILED;
1259 }
1260
1261 release_sendmsg = sendmsg = asl_msg_merge(sendmsg, msg);
1262 }
1263
1264 /* write to file descriptors */
1265 for (uint32_t i = 0; i < asl->out_count; i++) {
1266 if (shimmed) {
1267 if ((asl->out_list[i].fd != STDOUT_FILENO) && (asl->out_list[i].fd != STDERR_FILENO)) {
1268 continue; // new logging only support stdout/stderr
1269 }
1270 }
1271
1272 if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0)) {
1273 char *str;
1274
1275 uint32_t len = 0;
1276 str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
1277 if (str == NULL) continue;
1278
1279 status = write(asl->out_list[i].fd, str, len - 1);
1280 if (status < 0)
1281 {
1282 /* soft error for fd 2 (stderr) */
1283 if (asl->out_list[i].fd == 2) status = 0;
1284 asl->out_list[i].fd = -1;
1285 } else {
1286 status = 0;
1287 }
1288
1289 free(str);
1290 }
1291 }
1292 if (release_sendmsg) {
1293 asl_msg_release(release_sendmsg);
1294 }
1295
1296 return status;
1297}
1298
f3df4c03
A
1299static ASL_STATUS
1300_asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
1301{
af7d442c 1302 uint32_t len, level, lmask, outstatus, objtype;
f3df4c03
A
1303 const char *sstr, *fstr;
1304 struct timeval tval = {0, 0};
1305 int status;
1306 int use_global_lock = 0;
1307 kern_return_t kstatus;
1308 asl_msg_t *sendmsg;
1309 asl_msg_t *qd_msg = NULL;
1310 asl_client_t *asl = NULL;
1311 static dispatch_once_t noquota_once;
af7d442c 1312 __block int log_quota_msg = 0;
f3df4c03 1313
5222c21d 1314 if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
81582353 1315
f3df4c03
A
1316 if (obj == NULL)
1317 {
1318 asl = _asl_open_default();
1319 if (asl == NULL) return ASL_STATUS_FAILED;
1320 use_global_lock = 1;
1321 objtype = ASL_TYPE_CLIENT;
1322 }
1323 else
1324 {
1325 objtype = asl_get_type(obj);
1326 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
f3df4c03
A
1327 }
1328
5222c21d 1329 level = eval & EVAL_LEVEL_MASK;
f3df4c03 1330 if (level > 7) level = 7;
f3df4c03
A
1331 lmask = ASL_FILTER_MASK(level);
1332
1333 if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
1334
1335 status = gettimeofday(&tval, NULL);
1336 if (status != 0)
1337 {
1338 time_t tick = time(NULL);
1339 tval.tv_sec = tick;
1340 tval.tv_usec = 0;
1341 }
1342
1343 sstr = NULL;
1344 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1345 if (status != 0) sstr = NULL;
1346
1347 fstr = NULL;
1348 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1349 if (status != 0) fstr = NULL;
1350
1351 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1352 if (sendmsg == NULL) return ASL_STATUS_FAILED;
1353
1354 /* Set "ASLOption store" if tunneling */
5222c21d 1355 if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
81582353
A
1356
1357 outstatus = -1;
1358
1359 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1360
f3df4c03
A
1361 sendmsg = asl_msg_merge(sendmsg, msg);
1362
1363 if (objtype != ASL_TYPE_CLIENT)
1364 {
1365 asl_append(obj, (asl_object_t)sendmsg);
1366 asl_msg_release(sendmsg);
1367 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1368 return ASL_STATUS_OK;
1369 }
81582353
A
1370
1371 /*
1372 * If there is an aslfile this is a stand-alone file client.
1373 * Just save to the file.
1374 */
1375 if (asl->aslfile != NULL)
1376 {
1377 outstatus = ASL_STATUS_FAILED;
1378
f3df4c03 1379 if (sendmsg != NULL)
81582353 1380 {
f3df4c03 1381 outstatus = asl_file_save(asl->aslfile, sendmsg, &(asl->aslfileid));
81582353
A
1382 asl->aslfileid++;
1383 }
1384
f3df4c03 1385 asl_msg_release(sendmsg);
81582353
A
1386
1387 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1388 return outstatus;
1389 }
1390
81582353
A
1391 outstatus = 0;
1392
f3df4c03
A
1393 /*
1394 * ASL message quota
1395 * Quotas are disabled if:
1396 * - a remote control filter is in place (EVAL_TUNNEL)
1397 * - Environment variable ASL_QUOTA_DISABLED == 1
1398 * - /etc/asl/.noquota existed at the time that the process started
1399 *
5222c21d 1400 * We just check /etc/asl/.noquota once, since it would be
f3df4c03 1401 * expensive to stat() for every log message.
5222c21d
A
1402 *
1403 * We only check the Environment variable once, since getenv() is
1404 * not thread safe. If someone is changing the environment,
1405 * this can crash.
f3df4c03 1406 */
5222c21d 1407
f3df4c03
A
1408 dispatch_once(&noquota_once, ^{
1409 struct stat sb;
1410 memset(&sb, 0, sizeof(struct stat));
5222c21d
A
1411
1412 int save_errno = errno;
1413
1414 if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
f3df4c03
A
1415 {
1416 _asl_global.quota = UINT32_MAX;
f3df4c03 1417 }
5222c21d
A
1418 else
1419 {
1420 const char *qtest = getenv(NOQUOTA_ENV);
af7d442c
A
1421 if ((qtest != NULL) && (!strcmp(qtest, "1")))
1422 {
1423 _asl_global.quota = UINT32_MAX;
1424 log_quota_msg = 1;
1425 }
5222c21d
A
1426 }
1427
1428 /* reset errno since we want stat() to fail silently */
1429 errno = save_errno;
1430 });
1431
af7d442c
A
1432 if (log_quota_msg != 0)
1433 {
1434 qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
1435 asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
1436 }
1437
f3df4c03 1438 if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
81582353
A
1439 {
1440 time_t last_send = _asl_global.last_send;
1441 time_t last_oq = _asl_global.last_oq_msg;
1442 uint32_t qcurr = _asl_global.quota;
1443 time_t delta;
1444 uint32_t qinc, qnew;
1445
1446 qnew = qcurr;
1447
1448 /* add QUOTA_MPS to quota for each second we've been idle */
1449 if (tval.tv_sec > last_send)
1450 {
1451 delta = tval.tv_sec - last_send;
1452
1453 qinc = QUOTA_MPH;
1454 if (delta < (QUOTA_MPH / QUOTA_MPS)) qinc = delta * QUOTA_MPS;
1455
1456 qnew = MIN(QUOTA_MPH, qcurr + qinc);
1457 OSAtomicCompareAndSwapLongBarrier(last_send, tval.tv_sec, (long *)&_asl_global.last_send);
1458 }
1459
1460 if (qnew == 0)
1461 {
1462 if ((tval.tv_sec - last_oq) > QUOTA_MSG_INTERVAL)
1463 {
1464 eval |= EVAL_QUOTA;
1465 OSAtomicCompareAndSwapLongBarrier(last_oq, tval.tv_sec, (long *)&_asl_global.last_oq_msg);
1466 }
1467 else
1468 {
5222c21d 1469 eval &= ~EVAL_SEND_ASL;
81582353
A
1470 }
1471 }
1472 else
1473 {
1474 OSAtomicCompareAndSwap32Barrier(qcurr, qnew - 1, (int32_t *)&_asl_global.quota);
1475 }
1476 }
1477
86a8bcf5
A
1478#if TARGET_OS_OSX
1479 if (eval & EVAL_MT_SHIM)
1480 {
1481 _asl_mt_shim_send_message(sendmsg);
1482 }
1483#endif
1484
3cdd567c 1485 _asl_global_init();
5222c21d 1486 if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
81582353
A
1487 {
1488 asl_string_t *send_str;
1489 const char *str;
1490 size_t vmsize;
1491
1492 if (eval & EVAL_QUOTA)
1493 {
f3df4c03
A
1494 asl_msg_set_key_val(sendmsg, ASL_KEY_LEVEL, QUOTA_LEVEL_STR);
1495 asl_msg_set_key_val(sendmsg, ASL_KEY_MSG, QUOTA_MSG);
81582353
A
1496 }
1497
f3df4c03
A
1498 if (qd_msg != NULL)
1499 {
1500 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, qd_msg, "raw");
1501 len = asl_string_length(send_str);
1502 vmsize = asl_string_allocated_size(send_str);
1503 str = asl_string_release_return_bytes(send_str);
af7d442c
A
1504 if (len != 0)
1505 {
1506 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1507 if (kstatus != KERN_SUCCESS)
1508 {
1509 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1510 }
1511 }
1512 else if (vmsize != 0)
1513 {
1514 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1515 }
f3df4c03
A
1516 asl_msg_release(qd_msg);
1517 }
5222c21d 1518
f3df4c03 1519 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
81582353 1520 len = asl_string_length(send_str);
5222c21d
A
1521
1522 if (len > LIBASL_MAX_MSG_SIZE)
1523 {
1524 char tmp[256];
1525
1526 snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
1527 asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
1528
1529 asl_string_release(send_str);
1530 len = 0;
1531
1532 if (limitmsg != NULL)
1533 {
1534 /* Set "ASLOption store" if tunneling */
1535 if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
1536
1537 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
1538 len = asl_string_length(send_str);
1539 asl_msg_release(limitmsg);
1540 }
1541 }
1542
81582353 1543 vmsize = asl_string_allocated_size(send_str);
f3df4c03 1544 str = asl_string_release_return_bytes(send_str);
81582353
A
1545
1546 if (len != 0)
1547 {
1548 /* send a mach message to syslogd */
1549 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1550 if (kstatus != KERN_SUCCESS)
1551 {
30cde84f
A
1552 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1553 outstatus = -1;
81582353
A
1554 }
1555 }
1556 else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1557 }
1558
f3df4c03 1559 if ((sendmsg != NULL) && (asl->out_count > 0))
81582353 1560 {
af7d442c 1561 status = _asl_send_message_text(asl, sendmsg, obj, eval, msg, mstr, false);
81582353
A
1562 }
1563
f3df4c03 1564 asl_msg_release(sendmsg);
81582353
A
1565
1566 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1567
1568 return outstatus;
1569}
1570
af7d442c
A
1571static void
1572os_log_with_args_wrapper(void *addr, int level, const char *format, ...)
1573{
1574 va_list ap;
1575 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
1576 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1577 os_log_type_t type = shim_asl_to_log_type[level];
1578
1579 va_start(ap, format);
1580 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
1581 va_end(ap);
1582}
1583
81582353
A
1584/*
1585 * asl_send: send a message
f3df4c03 1586 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
81582353
A
1587 * has been used to set all of a message's attributes.
1588 * eval: hints about what to do with the message
f3df4c03 1589 * msg: an asl message
81582353
A
1590 * returns 0 for success, non-zero for failure
1591 */
f3df4c03 1592__private_extern__ ASL_STATUS
af7d442c 1593asl_client_internal_send(asl_object_t obj, asl_object_t msg, void *addr)
81582353 1594{
f3df4c03
A
1595 int status = ASL_STATUS_OK;
1596 uint32_t eval = _asl_evaluate_send(obj, msg, -1);
af7d442c
A
1597
1598 const char *message = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_MSG);
1599
1600 if ((eval & EVAL_SEND_TRACE) && message && message[0] && os_log_shim_enabled(addr))
1601 {
1602 int level = ASL_LEVEL_DEBUG;
1603 const char *lval = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_LEVEL);
1604 if (lval != NULL) level = atoi(lval);
1605
1606 /*
1607 * If the return address and the format string are from different
1608 * binaries, os_log_with_args will not record the return address.
1609 * Work around this by passing a dynamic format string.
1610 */
1611 char dynamic_format[] = "%s";
1612 os_log_with_args_wrapper(addr, level, dynamic_format, message);
1613
1614 if (eval & EVAL_TEXT_FILE)
1615 {
1616 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, NULL, true);
1617 }
1618 }
1619 else if (eval & EVAL_ASL)
1620 {
1621 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
1622 }
81582353
A
1623
1624 return status;
1625}
1626
f3df4c03
A
1627#pragma mark -
1628#pragma mark auxiliary files and URLs
1629
1630static ASL_STATUS
81582353
A
1631_asl_aux_save_context(asl_aux_context_t *ctx)
1632{
f3df4c03 1633 if (ctx == NULL) return ASL_STATUS_FAILED;
81582353
A
1634
1635 pthread_mutex_lock(&_asl_global.lock);
1636
1637 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, (_asl_global.aux_count + 1) * sizeof(asl_aux_context_t *));
1638 if (_asl_global.aux_ctx == NULL)
1639 {
1640 _asl_global.aux_count = 0;
f3df4c03
A
1641 pthread_mutex_unlock(&_asl_global.lock);
1642 return ASL_STATUS_FAILED;
81582353
A
1643 }
1644
1645 _asl_global.aux_ctx[_asl_global.aux_count++] = ctx;
1646
1647 pthread_mutex_unlock(&_asl_global.lock);
1648
f3df4c03 1649 return ASL_STATUS_OK;
81582353
A
1650}
1651
1652/*
1653 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1654 * will be saved at the time that the auxiliary file is created. The message will include
1655 * any keys and values found in msg, and it will include the title and Uniform Type
1656 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1657 * new auxiliary file.
1658 */
f3df4c03 1659static ASL_STATUS
81582353
A
1660_asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *url, int *out_fd)
1661{
1662 asl_msg_t *aux;
1663 asl_string_t *send_str;
1664 const char *str;
1665 fileport_t fileport;
1666 kern_return_t kstatus;
1667 size_t len, vmsize;
1668 uint32_t newurllen, where;
1669 int status, fd, fdpair[2];
1670 caddr_t newurl;
1671 dispatch_queue_t pipe_q;
1672 dispatch_io_t pipe_channel;
1673 dispatch_semaphore_t sem;
1674
1675 aux = asl_msg_new(ASL_TYPE_MSG);
1676
f3df4c03
A
1677 if (url != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url);
1678 if (title != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title);
1679 if (uti == NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data");
1680 else asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti);
81582353
A
1681
1682 aux = asl_msg_merge(aux, msg);
1683
1684 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1685 if (out_fd == NULL)
1686 {
f3df4c03 1687 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
81582353
A
1688 status = _asl_send_message(NULL, eval, aux, NULL);
1689 asl_msg_release(aux);
1690 return status;
1691 }
1692
1693 where = asl_store_location();
81582353
A
1694 if (where == ASL_STORE_LOCATION_MEMORY)
1695 {
1696 /* create a pipe */
81582353 1697 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
f3df4c03 1698 if (ctx == NULL) return ASL_STATUS_FAILED;
81582353
A
1699
1700 status = pipe(fdpair);
1701 if (status < 0)
1702 {
1703 free(ctx);
f3df4c03 1704 return ASL_STATUS_FAILED;
81582353
A
1705 }
1706
1707 /* give read end to dispatch_io_read */
1708 fd = fdpair[0];
1709 sem = dispatch_semaphore_create(0);
1710 ctx->sem = sem;
1711 ctx->fd = fdpair[1];
1712
1713 status = _asl_aux_save_context(ctx);
f3df4c03 1714 if (status != ASL_STATUS_OK)
81582353
A
1715 {
1716 close(fdpair[0]);
1717 close(fdpair[1]);
1718 dispatch_release(sem);
1719 free(ctx);
f3df4c03 1720 return ASL_STATUS_FAILED;
81582353
A
1721 }
1722
f3df4c03 1723 pipe_q = dispatch_queue_create("ASL_AUX_PIPE_Q", NULL);
81582353
A
1724 pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
1725 close(fd);
1726 });
1727
1728 *out_fd = fdpair[1];
1729
1730 dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
1731
1732 dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
1733 if (err == 0)
1734 {
1735 size_t len = dispatch_data_get_size(pipedata);
1736 if (len > 0)
1737 {
1738 const char *bytes = NULL;
1739 char *encoded;
1740 uint32_t eval;
1741
1742 dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
1743 encoded = asl_core_encode_buffer(bytes, len);
1744 asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded);
1745 free(encoded);
f3df4c03 1746 eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
81582353
A
1747 _asl_send_message(NULL, eval, aux, NULL);
1748 asl_msg_release(aux);
1749 dispatch_release(md);
1750 }
1751 }
1752
1753 if (done)
1754 {
1755 dispatch_semaphore_signal(sem);
1756 dispatch_release(pipe_channel);
1757 dispatch_release(pipe_q);
1758 }
1759 });
1760
f3df4c03 1761 return ASL_STATUS_OK;
81582353
A
1762 }
1763
30cde84f 1764 _asl_global_init();
f3df4c03 1765 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED;
81582353
A
1766
1767 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw");
1768 len = asl_string_length(send_str);
1769 vmsize = asl_string_allocated_size(send_str);
f3df4c03 1770 str = asl_string_release_return_bytes(send_str);
81582353
A
1771
1772 if (len == 0)
1773 {
1774 asl_msg_release(aux);
1775 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
f3df4c03 1776 return ASL_STATUS_FAILED;
81582353
A
1777 }
1778
1779 status = 0;
1780 fileport = MACH_PORT_NULL;
1781 status = KERN_SUCCESS;
1782
1783 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1784 if (kstatus != KERN_SUCCESS)
1785 {
30cde84f
A
1786 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1787 asl_msg_release(aux);
1788 return ASL_STATUS_FAILED;
81582353
A
1789 }
1790
1791 if (status != 0)
1792 {
1793 asl_msg_release(aux);
1794 return status;
1795 }
1796
1797 if (newurl != NULL)
1798 {
1799 asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, newurl);
1800 vm_deallocate(mach_task_self(), (vm_address_t)newurl, newurllen);
1801 }
1802
1803 if (fileport == MACH_PORT_NULL)
1804 {
1805 asl_msg_release(aux);
f3df4c03 1806 return ASL_STATUS_FAILED;
81582353
A
1807 }
1808
1809 fd = fileport_makefd(fileport);
1810 mach_port_deallocate(mach_task_self(), fileport);
1811 if (fd < 0)
1812 {
1813 asl_msg_release(aux);
1814 status = -1;
1815 }
1816 else
1817 {
1818 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1819 if (ctx == NULL)
1820 {
1821 status = -1;
1822 }
1823 else
1824 {
1825 *out_fd = fd;
1826
1827 ctx->fd = fd;
1828 ctx->msg = aux;
1829
1830 status = _asl_aux_save_context(ctx);
1831 }
1832 }
1833
1834 return status;
1835}
1836
1837int
f3df4c03 1838asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_fd)
81582353
A
1839{
1840 if (out_fd == NULL) return -1;
1841
f3df4c03
A
1842 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd);
1843 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
1844}
1845
1846int
f3df4c03 1847asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url)
81582353 1848{
f3df4c03
A
1849 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL);
1850 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
1851}
1852
1853/*
1854 * Close an auxiliary file.
1855 * Sends the cached auxiliary message to syslogd.
f3df4c03 1856 * Returns 0 on success, -1 on error.
81582353
A
1857 */
1858int
1859asl_close_auxiliary_file(int fd)
1860{
1861 int i, j, status;
1862 asl_msg_t *aux_msg;
1863 dispatch_semaphore_t aux_sem = NULL;
1864
1865 pthread_mutex_lock(&(_asl_global.lock));
1866
1867 aux_msg = NULL;
1868 status = -1;
1869
1870 for (i = 0; i < _asl_global.aux_count; i++)
1871 {
1872 if (_asl_global.aux_ctx[i]->fd == fd)
1873 {
1874 status = 0;
1875
1876 aux_msg = _asl_global.aux_ctx[i]->msg;
1877 aux_sem = _asl_global.aux_ctx[i]->sem;
1878
1879 free(_asl_global.aux_ctx[i]);
1880
1881 for (j = i + 1; j < _asl_global.aux_count; i++, j++)
1882 {
1883 _asl_global.aux_ctx[i] = _asl_global.aux_ctx[j];
1884 }
1885
1886 _asl_global.aux_count--;
1887
1888 if (_asl_global.aux_count == 0)
1889 {
1890 free(_asl_global.aux_ctx);
1891 _asl_global.aux_ctx = NULL;
1892 }
1893 else
1894 {
1895 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, _asl_global.aux_count * sizeof(asl_aux_context_t *));
1896 if (_asl_global.aux_ctx == NULL)
1897 {
1898 _asl_global.aux_count = 0;
1899 status = -1;
1900 }
1901 }
1902
1903 break;
1904 }
1905 }
1906
1907 pthread_mutex_unlock(&(_asl_global.lock));
1908
1909 close(fd);
1910
1911 if (aux_msg != NULL)
1912 {
f3df4c03 1913 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux_msg, -1);
81582353
A
1914 if (_asl_send_message(NULL, eval, aux_msg, NULL) != ASL_STATUS_OK) status = -1;
1915 asl_msg_release(aux_msg);
1916 }
1917
1918 if (aux_sem != NULL)
1919 {
1920 dispatch_semaphore_wait(aux_sem, DISPATCH_TIME_FOREVER);
1921 dispatch_release(aux_sem);
1922 }
1923
1924 return status;
1925}
1926
f3df4c03 1927#pragma mark -
81582353 1928
f3df4c03 1929asl_msg_t *
81582353
A
1930_asl_server_control_query(void)
1931{
f3df4c03
A
1932 asl_msg_list_t *list = NULL;
1933 char *res;
81582353
A
1934 uint32_t len, reslen, status;
1935 uint64_t cmax, qmin;
1936 kern_return_t kstatus;
1937 caddr_t vmstr;
1938 asl_msg_t *m = NULL;
1939 static const char ctlstr[] = "1\nQ [= ASLOption control]\n";
1940
30cde84f 1941 _asl_global_init();
81582353
A
1942 if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
1943
1944 len = strlen(ctlstr) + 1;
1945
1946 qmin = 0;
1947 cmax = 0;
1948 res = NULL;
1949 reslen = 0;
1950
5222c21d 1951 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
81582353
A
1952 if (kstatus != KERN_SUCCESS) return NULL;
1953
1954 memmove(vmstr, ctlstr, len);
1955
1956 status = 0;
1957 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
30cde84f 1958 if (kstatus != KERN_SUCCESS) return NULL;
f3df4c03
A
1959
1960 list = asl_msg_list_from_string(res);
81582353
A
1961 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1962
1963 if (list == NULL) return NULL;
1964 if (list->count > 0) m = asl_msg_retain(list->msg[0]);
f3df4c03
A
1965 asl_msg_list_release(list);
1966 return m;
81582353
A
1967}
1968
f3df4c03
A
1969/*
1970 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1971 */
81582353
A
1972int
1973asl_store_location()
1974{
1975 kern_return_t kstatus;
1976 char *res;
1977 uint32_t reslen, status;
1978 uint64_t cmax;
1979
30cde84f 1980 _asl_global_init();
81582353
A
1981 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
1982
1983 res = NULL;
1984 reslen = 0;
1985 cmax = 0;
1986 status = ASL_STATUS_OK;
1987
1988 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
30cde84f 1989 if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
81582353
A
1990
1991 /* res should never be returned, but just to be certain we don't leak VM ... */
1992 if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1993
81582353
A
1994 if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
1995 return ASL_STORE_LOCATION_FILE;
1996}
1997
f3df4c03
A
1998asl_object_t
1999asl_open_path(const char *path, uint32_t opts)
81582353 2000{
f3df4c03
A
2001 struct stat sb;
2002 asl_file_t *fout = NULL;
2003 asl_store_t *sout = NULL;
81582353 2004
f3df4c03 2005 if (opts == 0) opts = ASL_OPT_OPEN_READ;
81582353 2006
f3df4c03 2007 if (opts & ASL_OPT_OPEN_READ)
81582353 2008 {
f3df4c03
A
2009 if (path == NULL)
2010 {
2011 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT, &sout) != ASL_STATUS_OK) return NULL;
2012 return (asl_object_t)sout;
2013 }
81582353 2014
f3df4c03
A
2015 memset(&sb, 0, sizeof(struct stat));
2016 if (stat(path, &sb) < 0) return NULL;
81582353 2017
f3df4c03 2018 if (sb.st_mode & S_IFREG)
81582353 2019 {
f3df4c03
A
2020 if (asl_file_open_read(path, &fout) != ASL_STATUS_OK) return NULL;
2021 return (asl_object_t)fout;
81582353 2022 }
f3df4c03 2023 else if (sb.st_mode & S_IFDIR)
81582353 2024 {
f3df4c03
A
2025 if (asl_store_open_read(path, &sout) != ASL_STATUS_OK) return NULL;
2026 return (asl_object_t)sout;
81582353 2027 }
f3df4c03
A
2028
2029 return NULL;
2030 }
2031 else if (opts & ASL_OPT_OPEN_WRITE)
2032 {
2033 if (path == NULL) return NULL;
2034
2035 memset(&sb, 0, sizeof(struct stat));
2036 if (stat(path, &sb) < 0)
81582353 2037 {
f3df4c03
A
2038 if (errno != ENOENT) return NULL;
2039
2040 if (opts & ASL_OPT_CREATE_STORE)
2041 {
2042 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
5222c21d 2043 return (asl_object_t)sout;
f3df4c03
A
2044 }
2045 else
2046 {
2047 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2048 return (asl_object_t)fout;
2049 }
81582353 2050 }
f3df4c03 2051 else if (sb.st_mode & S_IFREG)
81582353 2052 {
f3df4c03
A
2053 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2054 return (asl_object_t)fout;
81582353 2055 }
f3df4c03 2056 else if (sb.st_mode & S_IFDIR)
81582353 2057 {
f3df4c03
A
2058 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
2059 return (asl_object_t)sout;
81582353 2060 }
81582353
A
2061 }
2062
f3df4c03 2063 return NULL;
81582353 2064}