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