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