2 * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
37 #include <sys/fcntl.h>
38 #include <sys/param.h>
39 #include <sys/fileport.h>
40 #include <crt_externs.h>
44 #include <mach/mach.h>
45 #include <mach/std_types.h>
47 #include <mach/mach_types.h>
48 #include <sys/types.h>
49 #include <servers/bootstrap.h>
50 #include <bootstrap_priv.h>
52 #include <dispatch/dispatch.h>
53 #include <libkern/OSAtomic.h>
54 #include <os/activity.h>
56 #include <os/log_private.h>
58 #include <asl_client.h>
61 #include <asl_msg_list.h>
62 #include <asl_store.h>
63 #include <asl_private.h>
65 #define forever for(;;)
67 #define FETCH_BATCH 256
69 #define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
70 #define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
73 * Clients get a max of 36000 messages per hour.
74 * Their quota gets refilled at a rate of 10 messages per second.
76 #define QUOTA_MPH 36000
78 #define QUOTA_MSG_INTERVAL 60
79 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
80 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
81 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
82 #define QUOTA_LEVEL ASL_LEVEL_CRIT
83 #define QUOTA_LEVEL_STR ASL_STRING_CRIT
86 * Limit the size of messages sent to syslogd.
88 #define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
90 static 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
102 static ASL_STATUS
_asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
);
103 static 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
);
104 __private_extern__ asl_client_t
*_asl_open_default();
107 uint32_t notify_register_plain(const char *name
, int *out_token
);
109 /* fork handling in asl_fd.c */
110 extern void _asl_redirect_fork_child(void);
116 dispatch_semaphore_t sem
;
125 uint64_t proc_filter
;
126 uint64_t master_filter
;
130 mach_port_t server_port
;
132 pthread_mutex_t lock
;
134 asl_aux_context_t
**aux_ctx
;
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
};
140 static const char *level_to_number_string
[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
142 #define ASL_SERVICE_NAME "com.apple.system.logger"
145 * Called from the child process inside fork() to clean up
146 * inherited state from the parent process.
148 * NB. A lock isn't required, since we're single threaded in this call.
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;
161 _asl_global
.server_port
= MACH_PORT_NULL
;
163 pthread_mutex_init(&(_asl_global
.lock
), NULL
);
165 _asl_redirect_fork_child();
169 * asl_remote_notify_name: returns the notification key for remote-control filter
170 * changes for this process.
173 asl_remote_notify_name()
175 pid_t pid
= getpid();
176 uid_t euid
= geteuid();
179 if (euid
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
);
180 else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
);
186 _asl_notify_open(int do_lock
)
191 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
193 _asl_global
.notify_count
++;
195 if (_asl_global
.notify_token
!= -1)
197 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
198 return ASL_STATUS_OK
;
201 if (_asl_global
.rc_change_token
== -1)
203 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
204 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
207 if (_asl_global
.master_token
== -1)
209 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
210 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
213 notify_name
= asl_remote_notify_name();
214 if (notify_name
!= NULL
)
216 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
218 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
221 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
223 if (_asl_global
.notify_token
== -1) return ASL_STATUS_FAILED
;
224 return ASL_STATUS_OK
;
231 pthread_mutex_lock(&_asl_global
.lock
);
233 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
235 if (_asl_global
.notify_count
> 0)
237 pthread_mutex_unlock(&_asl_global
.lock
);
241 if (_asl_global
.rc_change_token
>= 0) notify_cancel(_asl_global
.rc_change_token
);
242 _asl_global
.rc_change_token
= -1;
244 if (_asl_global
.master_token
>= 0) notify_cancel(_asl_global
.master_token
);
245 _asl_global
.master_token
= -1;
247 if (_asl_global
.notify_token
>= 0) notify_cancel(_asl_global
.notify_token
);
248 _asl_global
.notify_token
= -1;
250 pthread_mutex_unlock(&_asl_global
.lock
);
255 _asl_global_init(int reset
)
257 _asl_global
.server_port
= asl_core_get_service_port(reset
);
261 #pragma mark asl_client
264 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
266 asl_client_t
*asl
= asl_client_open(ident
, facility
, opts
);
267 if (asl
== NULL
) return NULL
;
270 if (!(opts
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
272 return (asl_object_t
)asl
;
276 asl_open_from_file(int fd
, const char *ident
, const char *facility
)
278 return (asl_object_t
)asl_client_open_from_file(fd
, ident
, facility
);
282 asl_close(asl_object_t obj
)
287 __private_extern__ asl_client_t
*
290 static dispatch_once_t once
;
292 dispatch_once(&once
, ^{
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.
298 _asl_global
.asl
= (asl_client_t
*)asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
300 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
301 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
303 /* Now call _asl_notify_open(0) to finish the work */
307 return _asl_global
.asl
;
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.
315 asl_add_output_file(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
)
317 int status
, use_global_lock
= 0;
320 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
322 asl
= (asl_client_t
*)client
;
325 asl
= _asl_open_default();
326 if (asl
== NULL
) return -1;
327 pthread_mutex_lock(&_asl_global
.lock
);
331 status
= asl_client_add_output_file(asl
, fd
, mfmt
, tfmt
, filter
, text_encoding
);
333 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
334 return (status
== ASL_STATUS_OK
) ? 0 : -1;
337 /* returns previous filter value or -1 on error */
339 asl_set_output_file_filter(asl_object_t client
, int fd
, int filter
)
342 int use_global_lock
= 0;
345 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
347 asl
= (asl_client_t
*)client
;
350 asl
= _asl_open_default();
351 if (asl
== NULL
) return -1;
352 pthread_mutex_lock(&_asl_global
.lock
);
356 last
= asl_client_set_output_file_filter(asl
, fd
, filter
);
358 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
362 /* SPI - Deprecated */
364 asl_add_output(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
366 return asl_add_output_file(client
, fd
, mfmt
, tfmt
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), text_encoding
);
369 /* SPI - Deprecated */
371 asl_add_log_file(asl_object_t client
, int fd
)
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
);
377 * asl_remove_output: stop writing log messages to the given file descriptor
380 asl_remove_output_file(asl_object_t client
, int fd
)
382 int status
, use_global_lock
= 0;
385 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
387 asl
= (asl_client_t
*)client
;
390 asl
= _asl_open_default();
391 if (asl
== NULL
) return -1;
392 pthread_mutex_lock(&_asl_global
.lock
);
396 status
= asl_client_remove_output_file(asl
, fd
);
398 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
399 return (status
== ASL_STATUS_OK
) ? 0 : -1;
403 asl_remove_output(asl_object_t client
, int fd
)
405 return asl_remove_output_file(client
, fd
);
409 asl_remove_log_file(asl_object_t client
, int fd
)
411 return asl_remove_output_file(client
, fd
);
414 /* returns previous filter value or -1 on error */
416 asl_set_filter(asl_object_t client
, int f
)
418 int last
, use_global_lock
= 0;
421 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
423 asl
= (asl_client_t
*)client
;
426 asl
= _asl_open_default();
427 if (asl
== NULL
) return -1;
428 pthread_mutex_lock(&_asl_global
.lock
);
432 last
= asl_client_set_filter(asl
, f
);
434 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
440 #pragma mark message sending
443 * Evaluate client / message / level to determine what to do with a message.
444 * Checks filters, tunneling, and log files.
445 * Returns the bits below, ORed with the message level.
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
454 _asl_evaluate_send(asl_object_t client
, asl_object_t m
, int slevel
)
457 asl_msg_t
*msg
= (asl_msg_t
*)m
;
458 uint32_t level
, lmask
, filter
, status
, tunnel
;
464 level
= ASL_LEVEL_DEBUG
;
465 if (slevel
>= 0) level
= slevel
;
468 if ((asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
) == 0) && (val
!= NULL
)) level
= atoi(val
);
470 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
471 else if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
473 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
))
475 /* sending to something other than a client */
476 return EVAL_ACTIVE
| EVAL_SEND_ASL
| level
;
479 asl
= (asl_client_t
*)client
;
480 if ((asl
!= NULL
) && (asl
->aslfile
!= NULL
)) return (EVAL_ASL_FILE
| level
);
482 if (asl
== NULL
) asl
= _asl_open_default();
485 eval
= EVAL_ACTIVE
| EVAL_DEFAULT_ACTION
| level
;
486 eval
&= ~EVAL_SEND_ASL
;
490 eval
= (asl_client_get_control(asl
) & EVAL_ACTION_MASK
) | level
;
492 filter
= asl
->filter
& 0xff;
493 tunnel
= (asl
->filter
& ASL_FILTER_MASK_TUNNEL
) >> 8;
494 if (tunnel
!= 0) eval
|= EVAL_TUNNEL
;
496 if ((asl
->options
& ASL_OPT_NO_REMOTE
) == 0)
498 pthread_mutex_lock(&_asl_global
.lock
);
500 if (_asl_global
.rc_change_token
>= 0)
502 /* initialize or re-check process-specific and master filters */
504 status
= notify_check(_asl_global
.rc_change_token
, &check
);
505 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
507 if (_asl_global
.master_token
>= 0)
510 status
= notify_get_state(_asl_global
.master_token
, &v64
);
511 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
514 if (_asl_global
.notify_token
>= 0)
517 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
518 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
523 if (_asl_global
.master_filter
& EVAL_ACTIVE
)
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
));
530 if ((_asl_global
.master_filter
& EVAL_LEVEL_MASK
) != 0) filter
= _asl_global
.proc_filter
& EVAL_LEVEL_MASK
;
533 if (_asl_global
.proc_filter
& EVAL_ACTIVE
)
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
));
540 if ((_asl_global
.proc_filter
& EVAL_LEVEL_MASK
) != 0) filter
= _asl_global
.proc_filter
& EVAL_LEVEL_MASK
;
543 pthread_mutex_unlock(&_asl_global
.lock
);
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
;
550 /* don't send MessageTracer messages to Activity Tracing */
552 if ((asl_msg_lookup(msg
, ASL_KEY_MESSAGETRACER
, &val
, NULL
) == 0) && (val
!= NULL
)) eval
&= ~EVAL_SEND_TRACE
;
554 /* don't send PowerManagement messages to Activity Tracing */
556 if ((asl_msg_lookup(msg
, ASL_KEY_POWERMANAGEMENT
, &val
, NULL
) == 0) && (val
!= NULL
)) eval
&= ~EVAL_SEND_TRACE
;
558 /* don't send control messages to Activity Tracing */
560 if ((asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
) == 0) && (val
!= NULL
)) eval
&= ~EVAL_SEND_TRACE
;
562 /* don't send CFLog messages to Activity Tracing */
564 if ((asl_msg_lookup(msg
, ASL_KEY_CFLOG_LOCAL_TIME
, &val
, NULL
) == 0) && (val
!= NULL
)) eval
&= ~EVAL_SEND_TRACE
;
567 if (((asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &val
, NULL
) == 0) && (val
!= NULL
)) ||
568 ((asl_msg_lookup(asl
->kvdict
, ASL_KEY_FACILITY
, &val
, NULL
) == 0) && (val
!= NULL
)))
570 /* don't send lastlog/utmp messages to Activity Tracing */
571 if (!strcmp(val
, FACILITY_LASTLOG
) || !strcmp(val
, FACILITY_UTMPX
)) eval
&= ~EVAL_SEND_TRACE
;
573 /* don't send LOG_INSTALL messages to Activity Tracing */
574 if (!strcmp(val
, asl_syslog_faciliy_num_to_name(LOG_INSTALL
))) eval
&= ~EVAL_SEND_TRACE
;
582 * Internal routine used by asl_vlog.
583 * msg: an asl messsage
584 * eval: log level and send flags for the message
585 * format: A formating string
586 * ap: va_list for the format
587 * returns 0 for success, non-zero for failure
590 __private_extern__ ASL_STATUS
591 _asl_lib_vlog_text(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
)
593 int saved_errno
= errno
;
595 char *str
, *fmt
, estr
[NL_TEXTMAX
];
596 uint32_t i
, len
, elen
, expand
;
598 if (format
== NULL
) return ASL_STATUS_INVALID_ARG
;
600 /* insert strerror for %m */
605 for (i
= 0; format
[i
] != '\0'; i
++)
607 if (format
[i
] == '%')
609 if (format
[i
+1] == '\0') len
++;
610 else if (format
[i
+1] == 'm')
613 strerror_r(saved_errno
, estr
, sizeof(estr
));
627 fmt
= (char *)format
;
631 fmt
= malloc(len
+ 1);
632 if (fmt
== NULL
) return ASL_STATUS_NO_MEMORY
;
636 for (i
= 0; format
[i
] != '\0'; i
++)
638 if (format
[i
] == '%')
640 if (format
[i
+1] == '\0')
643 else if ((format
[i
+1] == 'm') && (elen
!= 0))
645 memcpy(fmt
+len
, estr
, elen
);
651 fmt
[len
++] = format
[i
++];
652 fmt
[len
++] = format
[i
];
655 else fmt
[len
++] = format
[i
];
662 vasprintf(&str
, fmt
, ap
);
663 if (expand
!= 0) free(fmt
);
665 if (str
== NULL
) return ASL_STATUS_NO_MEMORY
;
667 status
= _asl_send_message_text(NULL
, NULL
, obj
, eval
, (asl_msg_t
*)msg
, str
, true);
675 * Internal routine used by asl_vlog.
676 * msg: an asl messsage
677 * eval: log level and send flags for the message
678 * format: A formating string
679 * ap: va_list for the format
680 * returns 0 for success, non-zero for failure
682 __private_extern__ ASL_STATUS
683 _asl_lib_vlog(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
)
685 int saved_errno
= errno
;
687 char *str
, *fmt
, estr
[NL_TEXTMAX
];
688 uint32_t i
, len
, elen
, expand
;
690 if (format
== NULL
) return ASL_STATUS_INVALID_ARG
;
692 /* insert strerror for %m */
697 for (i
= 0; format
[i
] != '\0'; i
++)
699 if (format
[i
] == '%')
701 if (format
[i
+1] == '\0') len
++;
702 else if (format
[i
+1] == 'm')
705 strerror_r(saved_errno
, estr
, sizeof(estr
));
719 fmt
= (char *)format
;
723 fmt
= malloc(len
+ 1);
724 if (fmt
== NULL
) return ASL_STATUS_NO_MEMORY
;
728 for (i
= 0; format
[i
] != '\0'; i
++)
730 if (format
[i
] == '%')
732 if (format
[i
+1] == '\0')
735 else if ((format
[i
+1] == 'm') && (elen
!= 0))
737 memcpy(fmt
+len
, estr
, elen
);
743 fmt
[len
++] = format
[i
++];
744 fmt
[len
++] = format
[i
];
747 else fmt
[len
++] = format
[i
];
754 vasprintf(&str
, fmt
, ap
);
755 if (expand
!= 0) free(fmt
);
757 if (str
== NULL
) return ASL_STATUS_NO_MEMORY
;
759 status
= _asl_send_message(obj
, eval
, (asl_msg_t
*)msg
, str
);
767 * Similar to asl_log, but take a va_list instead of a list of arguments.
768 * msg: an asl message
769 * level: the log level of the associated message
770 * format: A formating string
771 * ap: va_list for the format
772 * returns 0 for success, non-zero for failure
775 asl_vlog(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, va_list ap
)
777 ASL_STATUS status
= ASL_STATUS_OK
;
778 uint32_t eval
= _asl_evaluate_send(client
, msg
, level
);
779 void *addr
= __builtin_return_address(0);
781 if ((eval
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
))
784 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
785 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
786 os_log_type_t type
= shim_asl_to_log_type
[level
];
788 va_copy(ap_copy
, ap
);
789 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap_copy
, addr
);
792 if (eval
& EVAL_TEXT_FILE
)
794 status
= _asl_lib_vlog_text(client
, eval
, msg
, format
, ap
);
797 else if (eval
& EVAL_ASL
)
799 status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
802 return (status
== ASL_STATUS_OK
) ? 0 : -1;
807 * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
808 * forwards the call to _asl_lib_vlog.
809 * msg: an asl message
810 * eval: log level and send flags for the message
811 * format: A formating string
812 * ... args for format
813 * returns 0 for success, non-zero for failure
816 _asl_lib_log(asl_object_t client
, uint32_t eval
, asl_object_t msg
, const char *format
, ...)
824 va_start(ap
, format
);
825 status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
834 * Processes an ASL log message.
835 * msg: an asl message
836 * level: the log level of the associated message
837 * format: A formating string
838 * ... args for format
839 * returns 0 for success, non-zero for failure
842 asl_log(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, ...)
844 ASL_STATUS status
= ASL_STATUS_OK
;
845 uint32_t eval
= _asl_evaluate_send(client
, msg
, level
);
846 void *addr
= __builtin_return_address(0);
848 if ((eval
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
))
851 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
852 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
853 os_log_type_t type
= shim_asl_to_log_type
[level
];
855 va_start(ap
, format
);
856 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
);
859 if (eval
& EVAL_TEXT_FILE
)
862 va_start(ap
, format
);
863 status
= _asl_lib_vlog_text(client
, eval
, msg
, format
, ap
);
867 else if (eval
& EVAL_ASL
)
870 va_start(ap
, format
);
871 status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
875 return (status
== ASL_STATUS_OK
) ? 0 : -1;
880 * Like asl_log, supplies NULL client and msg.
881 * level: the log level of the associated message
882 * format: A formating string
883 * ... args for format
884 * returns 0 for success, non-zero for failure
887 asl_log_message(int level
, const char *format
, ...)
889 ASL_STATUS status
= ASL_STATUS_OK
;
890 uint32_t eval
= _asl_evaluate_send(NULL
, NULL
, level
);
891 void *addr
= __builtin_return_address(0);
893 if ((eval
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
))
896 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
897 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
898 os_log_type_t type
= shim_asl_to_log_type
[level
];
900 va_start(ap
, format
);
901 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
);
904 if (eval
& EVAL_TEXT_FILE
)
907 va_start(ap
, format
);
908 status
= _asl_lib_vlog_text(NULL
, eval
, NULL
, format
, ap
);
912 else if (eval
& EVAL_ASL
)
915 va_start(ap
, format
);
916 status
= _asl_lib_vlog(NULL
, eval
, NULL
, format
, ap
);
920 return (status
== ASL_STATUS_OK
) ? 0 : -1;
924 * asl_get_filter: gets the values for the local, master, and remote filters,
925 * and indicates which one is active.
928 asl_get_filter(asl_object_t client
, int *local
, int *master
, int *remote
, int *active
)
930 asl_client_t
*asl
, *asl_default
;
935 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
942 asl_default
= _asl_open_default();
944 asl
= (asl_client_t
*)client
;
945 if (asl
== NULL
) asl
= asl_default
;
946 if (asl
!= NULL
) l
= asl
->filter
& EVAL_LEVEL_MASK
;
948 if ((asl_default
!= NULL
) && (!(asl_default
->options
& ASL_OPT_NO_REMOTE
)))
950 pthread_mutex_lock(&_asl_global
.lock
);
952 if (_asl_global
.rc_change_token
>= 0)
954 /* initialize or re-check process-specific and master filters */
956 status
= notify_check(_asl_global
.rc_change_token
, &check
);
957 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
959 if (_asl_global
.master_token
>= 0)
962 status
= notify_get_state(_asl_global
.master_token
, &v64
);
963 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
966 if (_asl_global
.notify_token
>= 0)
969 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
970 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
975 m
= _asl_global
.master_filter
;
978 r
= _asl_global
.proc_filter
;
981 pthread_mutex_unlock(&_asl_global
.lock
);
984 if (local
!= NULL
) *local
= l
;
985 if (master
!= NULL
) *master
= m
;
986 if (remote
!= NULL
) *remote
= r
;
987 if (active
!= NULL
) *active
= x
;
992 /* SPI for SHIM control */
994 asl_set_local_control(asl_object_t client
, uint32_t filter
)
996 asl_client_t
*asl
= (asl_client_t
*)client
;
999 asl
= _asl_open_default();
1000 if (asl
== NULL
) return UINT32_MAX
;
1002 else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
;
1004 return asl_client_set_control(asl
, filter
);
1008 asl_get_local_control(asl_object_t client
)
1010 asl_client_t
*asl
= (asl_client_t
*)client
;
1013 asl
= _asl_open_default();
1014 if (asl
== NULL
) return UINT32_MAX
;
1016 else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
;
1018 return asl_client_get_control(asl
);
1022 * Sets PID and OSActivityID values in a new message.
1023 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
1026 asl_base_msg(asl_client_t
*asl
, uint32_t level
, const struct timeval
*tv
, const char *sstr
, const char *fstr
, const char *mstr
)
1031 os_activity_id_t osaid
;
1033 aux
= asl_msg_new(ASL_TYPE_MSG
);
1034 if (aux
== NULL
) return NULL
;
1037 if (level
<= 7) asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, level_to_number_string
[level
]);
1039 /* Time and TimeNanoSec */
1042 snprintf(aux_val
, sizeof(aux_val
), "%llu", (unsigned long long) tv
->tv_sec
);
1043 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
1045 snprintf(aux_val
, sizeof(aux_val
), "%d", tv
->tv_usec
* 1000);
1046 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
);
1050 if (mstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstr
);
1053 snprintf(aux_val
, sizeof(aux_val
), "%u", getpid());
1054 asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
);
1057 osaid
= os_activity_get_identifier(OS_ACTIVITY_CURRENT
, NULL
);
1060 snprintf(aux_val
, sizeof(aux_val
), "0x%016llx", osaid
);
1061 asl_msg_set_key_val(aux
, ASL_KEY_OS_ACTIVITY_ID
, aux_val
);
1065 if ((sstr
== NULL
) && (asl
!= NULL
))
1067 /* See if the client has a value for ASL_KEY_SENDER */
1068 status
= asl_msg_lookup((asl_msg_t
*)asl
->kvdict
, ASL_KEY_SENDER
, &sstr
, NULL
);
1069 if ((status
!= 0) || (sstr
== NULL
))
1073 /* See if the global cache has a value for ASL_KEY_SENDER */
1074 if (_asl_global
.sender
== NULL
)
1076 /* Get the process name with _NSGetArgv */
1077 char *name
= *(*_NSGetArgv());
1080 char *x
= strrchr(name
, '/');
1084 /* Set the cache value */
1085 pthread_mutex_lock(&_asl_global
.lock
);
1086 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
1087 pthread_mutex_unlock(&_asl_global
.lock
);
1091 if (_asl_global
.sender
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
);
1092 else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown");
1096 if (sstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, sstr
);
1099 if ((fstr
== NULL
) && (asl
!= NULL
))
1101 status
= asl_msg_lookup((asl_msg_t
*)asl
->kvdict
, ASL_KEY_FACILITY
, &fstr
, NULL
);
1102 if (status
!= 0) fstr
= NULL
;
1105 if (fstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, fstr
);
1112 * Possibly useful someday...
1115 asl_prepared_message(asl_client_t
*asl
, asl_msg_t
*msg
)
1117 uint32_t i
, len
, level
, outstatus
;
1118 const char *val
, *sstr
, *fstr
;
1119 struct timeval tval
= {0, 0};
1125 asl
= _asl_open_default();
1126 if (asl
== NULL
) return NULL
;
1129 status
= gettimeofday(&tval
, NULL
);
1132 time_t tick
= time(NULL
);
1138 status
= asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
);
1139 if (status
!= 0) val
= NULL
;
1141 level
= ASL_LEVEL_DEBUG
;
1142 if (val
!= NULL
) level
= atoi(val
);
1143 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
1146 status
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
);
1147 if (status
!= 0) sstr
= NULL
;
1150 status
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
);
1151 if (status
!= 0) fstr
= NULL
;
1153 out
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, NULL
);
1154 out
= asl_msg_merge(out
, msg
);
1161 _asl_set_option(asl_msg_t
*msg
, const char *opt
)
1163 const char *val
= NULL
;
1166 if (msg
== NULL
) return;
1167 if (opt
== NULL
) return;
1169 status
= asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
);
1170 if ((status
!= 0) || (val
== NULL
))
1172 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, opt
);
1176 char *option
= NULL
;
1177 asprintf(&option
, "%s %s", opt
, val
);
1178 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, option
);
1184 _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
)
1187 uint32_t level
, lmask
;
1188 asl_msg_t
*release_sendmsg
= NULL
;
1192 asl
= _asl_open_default();
1193 if (asl
== NULL
) return ASL_STATUS_FAILED
;
1195 uint32_t objtype
= asl_get_type(obj
);
1196 if (objtype
== ASL_TYPE_CLIENT
) asl
= (asl_client_t
*)obj
;
1200 level
= eval
& EVAL_LEVEL_MASK
;
1201 if (level
> 7) level
= 7;
1202 lmask
= ASL_FILTER_MASK(level
);
1204 if (sendmsg
== NULL
) {
1205 struct timeval tval
= {0, 0};
1206 const char *sstr
, *fstr
;
1208 status
= gettimeofday(&tval
, NULL
);
1210 time_t tick
= time(NULL
);
1216 status
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
);
1222 status
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
);
1226 sendmsg
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
);
1227 if (sendmsg
== NULL
) {
1228 return ASL_STATUS_FAILED
;
1231 release_sendmsg
= sendmsg
= asl_msg_merge(sendmsg
, msg
);
1234 /* write to file descriptors */
1235 for (uint32_t i
= 0; i
< asl
->out_count
; i
++) {
1237 if ((asl
->out_list
[i
].fd
!= STDOUT_FILENO
) && (asl
->out_list
[i
].fd
!= STDERR_FILENO
)) {
1238 continue; // new logging only support stdout/stderr
1242 if ((asl
->out_list
[i
].fd
>= 0) && (asl
->out_list
[i
].filter
!= 0) && ((asl
->out_list
[i
].filter
& lmask
) != 0)) {
1246 str
= asl_format_message(sendmsg
, asl
->out_list
[i
].mfmt
, asl
->out_list
[i
].tfmt
, asl
->out_list
[i
].encoding
, &len
);
1247 if (str
== NULL
) continue;
1249 status
= write(asl
->out_list
[i
].fd
, str
, len
- 1);
1252 /* soft error for fd 2 (stderr) */
1253 if (asl
->out_list
[i
].fd
== 2) status
= 0;
1254 asl
->out_list
[i
].fd
= -1;
1262 if (release_sendmsg
) {
1263 asl_msg_release(release_sendmsg
);
1270 _asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t
*msg
, const char *mstr
)
1272 uint32_t len
, level
, lmask
, outstatus
, objtype
;
1273 const char *sstr
, *fstr
;
1274 struct timeval tval
= {0, 0};
1276 int use_global_lock
= 0;
1277 kern_return_t kstatus
;
1279 asl_msg_t
*qd_msg
= NULL
;
1280 asl_client_t
*asl
= NULL
;
1281 static dispatch_once_t noquota_once
;
1282 __block
int log_quota_msg
= 0;
1284 if ((eval
& EVAL_ASL
) == 0) return ASL_STATUS_OK
;
1288 asl
= _asl_open_default();
1289 if (asl
== NULL
) return ASL_STATUS_FAILED
;
1290 use_global_lock
= 1;
1291 objtype
= ASL_TYPE_CLIENT
;
1295 objtype
= asl_get_type(obj
);
1296 if (objtype
== ASL_TYPE_CLIENT
) asl
= (asl_client_t
*)obj
;
1299 level
= eval
& EVAL_LEVEL_MASK
;
1300 if (level
> 7) level
= 7;
1301 lmask
= ASL_FILTER_MASK(level
);
1303 if ((objtype
== ASL_TYPE_CLIENT
) && (asl
->aslfile
!= NULL
)) use_global_lock
= 1;
1305 status
= gettimeofday(&tval
, NULL
);
1308 time_t tick
= time(NULL
);
1314 status
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
);
1315 if (status
!= 0) sstr
= NULL
;
1318 status
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
);
1319 if (status
!= 0) fstr
= NULL
;
1321 sendmsg
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
);
1322 if (sendmsg
== NULL
) return ASL_STATUS_FAILED
;
1324 /* Set "ASLOption store" if tunneling */
1325 if (eval
& EVAL_TUNNEL
) _asl_set_option(sendmsg
, ASL_OPT_STORE
);
1329 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
1331 sendmsg
= asl_msg_merge(sendmsg
, msg
);
1333 if (objtype
!= ASL_TYPE_CLIENT
)
1335 asl_append(obj
, (asl_object_t
)sendmsg
);
1336 asl_msg_release(sendmsg
);
1337 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1338 return ASL_STATUS_OK
;
1342 * If there is an aslfile this is a stand-alone file client.
1343 * Just save to the file.
1345 if (asl
->aslfile
!= NULL
)
1347 outstatus
= ASL_STATUS_FAILED
;
1349 if (sendmsg
!= NULL
)
1351 outstatus
= asl_file_save(asl
->aslfile
, sendmsg
, &(asl
->aslfileid
));
1355 asl_msg_release(sendmsg
);
1357 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1361 _asl_global_init(0);
1366 * Quotas are disabled if:
1367 * - a remote control filter is in place (EVAL_TUNNEL)
1368 * - Environment variable ASL_QUOTA_DISABLED == 1
1369 * - /etc/asl/.noquota existed at the time that the process started
1371 * We just check /etc/asl/.noquota once, since it would be
1372 * expensive to stat() for every log message.
1374 * We only check the Environment variable once, since getenv() is
1375 * not thread safe. If someone is changing the environment,
1379 dispatch_once(&noquota_once
, ^{
1381 memset(&sb
, 0, sizeof(struct stat
));
1383 int save_errno
= errno
;
1385 if (stat(NOQUOTA_FILE_PATH
, &sb
) == 0)
1387 _asl_global
.quota
= UINT32_MAX
;
1391 const char *qtest
= getenv(NOQUOTA_ENV
);
1392 if ((qtest
!= NULL
) && (!strcmp(qtest
, "1")))
1394 _asl_global
.quota
= UINT32_MAX
;
1399 /* reset errno since we want stat() to fail silently */
1403 if (log_quota_msg
!= 0)
1405 qd_msg
= asl_base_msg(asl
, QUOTA_LEVEL
, &tval
, sstr
, fstr
, QUOTA_DISABLED_MSG
);
1406 asl_msg_set_key_val(qd_msg
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
1409 if (((eval
& EVAL_TUNNEL
) == 0) && (_asl_global
.quota
!= UINT32_MAX
))
1411 time_t last_send
= _asl_global
.last_send
;
1412 time_t last_oq
= _asl_global
.last_oq_msg
;
1413 uint32_t qcurr
= _asl_global
.quota
;
1415 uint32_t qinc
, qnew
;
1419 /* add QUOTA_MPS to quota for each second we've been idle */
1420 if (tval
.tv_sec
> last_send
)
1422 delta
= tval
.tv_sec
- last_send
;
1425 if (delta
< (QUOTA_MPH
/ QUOTA_MPS
)) qinc
= delta
* QUOTA_MPS
;
1427 qnew
= MIN(QUOTA_MPH
, qcurr
+ qinc
);
1428 OSAtomicCompareAndSwapLongBarrier(last_send
, tval
.tv_sec
, (long *)&_asl_global
.last_send
);
1433 if ((tval
.tv_sec
- last_oq
) > QUOTA_MSG_INTERVAL
)
1436 OSAtomicCompareAndSwapLongBarrier(last_oq
, tval
.tv_sec
, (long *)&_asl_global
.last_oq_msg
);
1440 eval
&= ~EVAL_SEND_ASL
;
1445 OSAtomicCompareAndSwap32Barrier(qcurr
, qnew
- 1, (int32_t *)&_asl_global
.quota
);
1449 if ((_asl_global
.server_port
!= MACH_PORT_NULL
) && (eval
& EVAL_SEND_ASL
))
1451 asl_string_t
*send_str
;
1455 if (eval
& EVAL_QUOTA
)
1457 asl_msg_set_key_val(sendmsg
, ASL_KEY_LEVEL
, QUOTA_LEVEL_STR
);
1458 asl_msg_set_key_val(sendmsg
, ASL_KEY_MSG
, QUOTA_MSG
);
1463 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, qd_msg
, "raw");
1464 len
= asl_string_length(send_str
);
1465 vmsize
= asl_string_allocated_size(send_str
);
1466 str
= asl_string_release_return_bytes(send_str
);
1469 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1470 if (kstatus
!= KERN_SUCCESS
)
1472 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1475 else if (vmsize
!= 0)
1477 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1479 asl_msg_release(qd_msg
);
1482 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, sendmsg
, "raw");
1483 len
= asl_string_length(send_str
);
1485 if (len
> LIBASL_MAX_MSG_SIZE
)
1489 snprintf(tmp
, sizeof(tmp
), SIZE_LIMIT_MSG
, len
, LIBASL_MAX_MSG_SIZE
);
1490 asl_msg_t
*limitmsg
= asl_base_msg(asl
, ASL_LEVEL_CRIT
, &tval
, sstr
, fstr
, tmp
);
1492 asl_string_release(send_str
);
1495 if (limitmsg
!= NULL
)
1497 /* Set "ASLOption store" if tunneling */
1498 if (eval
& EVAL_TUNNEL
) _asl_set_option(limitmsg
, ASL_OPT_STORE
);
1500 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, limitmsg
, "raw");
1501 len
= asl_string_length(send_str
);
1502 asl_msg_release(limitmsg
);
1506 vmsize
= asl_string_allocated_size(send_str
);
1507 str
= asl_string_release_return_bytes(send_str
);
1511 /* send a mach message to syslogd */
1512 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1513 if (kstatus
!= KERN_SUCCESS
)
1515 /* retry once if the call failed */
1516 _asl_global_init(1);
1517 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1518 if (kstatus
!= KERN_SUCCESS
)
1520 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1525 else if (vmsize
>0) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1528 if ((sendmsg
!= NULL
) && (asl
->out_count
> 0))
1530 status
= _asl_send_message_text(asl
, sendmsg
, obj
, eval
, msg
, mstr
, false);
1533 asl_msg_release(sendmsg
);
1535 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1541 os_log_with_args_wrapper(void *addr
, int level
, const char *format
, ...)
1544 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
1545 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
1546 os_log_type_t type
= shim_asl_to_log_type
[level
];
1548 va_start(ap
, format
);
1549 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
);
1554 * asl_send: send a message
1555 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1556 * has been used to set all of a message's attributes.
1557 * eval: hints about what to do with the message
1558 * msg: an asl message
1559 * returns 0 for success, non-zero for failure
1561 __private_extern__ ASL_STATUS
1562 asl_client_internal_send(asl_object_t obj
, asl_object_t msg
, void *addr
)
1564 int status
= ASL_STATUS_OK
;
1565 uint32_t eval
= _asl_evaluate_send(obj
, msg
, -1);
1567 const char *message
= asl_msg_get_val_for_key((asl_msg_t
*)msg
, ASL_KEY_MSG
);
1569 if ((eval
& EVAL_SEND_TRACE
) && message
&& message
[0] && os_log_shim_enabled(addr
))
1571 int level
= ASL_LEVEL_DEBUG
;
1572 const char *lval
= asl_msg_get_val_for_key((asl_msg_t
*)msg
, ASL_KEY_LEVEL
);
1573 if (lval
!= NULL
) level
= atoi(lval
);
1576 * If the return address and the format string are from different
1577 * binaries, os_log_with_args will not record the return address.
1578 * Work around this by passing a dynamic format string.
1580 char dynamic_format
[] = "%s";
1581 os_log_with_args_wrapper(addr
, level
, dynamic_format
, message
);
1583 if (eval
& EVAL_TEXT_FILE
)
1585 status
= _asl_send_message_text(NULL
, NULL
, obj
, eval
, (asl_msg_t
*)msg
, NULL
, true);
1588 else if (eval
& EVAL_ASL
)
1590 status
= _asl_send_message(obj
, eval
, (asl_msg_t
*)msg
, NULL
);
1597 #pragma mark auxiliary files and URLs
1600 _asl_aux_save_context(asl_aux_context_t
*ctx
)
1602 if (ctx
== NULL
) return ASL_STATUS_FAILED
;
1604 pthread_mutex_lock(&_asl_global
.lock
);
1606 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count
+ 1) * sizeof(asl_aux_context_t
*));
1607 if (_asl_global
.aux_ctx
== NULL
)
1609 _asl_global
.aux_count
= 0;
1610 pthread_mutex_unlock(&_asl_global
.lock
);
1611 return ASL_STATUS_FAILED
;
1614 _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
;
1616 pthread_mutex_unlock(&_asl_global
.lock
);
1618 return ASL_STATUS_OK
;
1622 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1623 * will be saved at the time that the auxiliary file is created. The message will include
1624 * any keys and values found in msg, and it will include the title and Uniform Type
1625 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1626 * new auxiliary file.
1629 _asl_auxiliary(asl_msg_t
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
)
1632 asl_string_t
*send_str
;
1634 fileport_t fileport
;
1635 kern_return_t kstatus
;
1637 uint32_t newurllen
, where
;
1638 int status
, fd
, fdpair
[2];
1640 dispatch_queue_t pipe_q
;
1641 dispatch_io_t pipe_channel
;
1642 dispatch_semaphore_t sem
;
1644 aux
= asl_msg_new(ASL_TYPE_MSG
);
1646 if (url
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
);
1647 if (title
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
);
1648 if (uti
== NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data");
1649 else asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
);
1651 aux
= asl_msg_merge(aux
, msg
);
1653 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1656 uint32_t eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1);
1657 status
= _asl_send_message(NULL
, eval
, aux
, NULL
);
1658 asl_msg_release(aux
);
1662 where
= asl_store_location();
1663 if (where
== ASL_STORE_LOCATION_MEMORY
)
1666 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1667 if (ctx
== NULL
) return ASL_STATUS_FAILED
;
1669 status
= pipe(fdpair
);
1673 return ASL_STATUS_FAILED
;
1676 /* give read end to dispatch_io_read */
1678 sem
= dispatch_semaphore_create(0);
1680 ctx
->fd
= fdpair
[1];
1682 status
= _asl_aux_save_context(ctx
);
1683 if (status
!= ASL_STATUS_OK
)
1687 dispatch_release(sem
);
1689 return ASL_STATUS_FAILED
;
1692 pipe_q
= dispatch_queue_create("ASL_AUX_PIPE_Q", NULL
);
1693 pipe_channel
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){
1697 *out_fd
= fdpair
[1];
1699 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
);
1701 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){
1704 size_t len
= dispatch_data_get_size(pipedata
);
1707 const char *bytes
= NULL
;
1711 dispatch_data_t md
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
);
1712 encoded
= asl_core_encode_buffer(bytes
, len
);
1713 asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
);
1715 eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1);
1716 _asl_send_message(NULL
, eval
, aux
, NULL
);
1717 asl_msg_release(aux
);
1718 dispatch_release(md
);
1724 dispatch_semaphore_signal(sem
);
1725 dispatch_release(pipe_channel
);
1726 dispatch_release(pipe_q
);
1730 return ASL_STATUS_OK
;
1733 _asl_global_init(0);
1734 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STATUS_FAILED
;
1736 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw");
1737 len
= asl_string_length(send_str
);
1738 vmsize
= asl_string_allocated_size(send_str
);
1739 str
= asl_string_release_return_bytes(send_str
);
1743 asl_msg_release(aux
);
1744 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1745 return ASL_STATUS_FAILED
;
1749 fileport
= MACH_PORT_NULL
;
1750 status
= KERN_SUCCESS
;
1752 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1753 if (kstatus
!= KERN_SUCCESS
)
1755 /* retry once if the call failed */
1756 _asl_global_init(1);
1757 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1758 if (kstatus
!= KERN_SUCCESS
)
1760 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1761 asl_msg_release(aux
);
1762 return ASL_STATUS_FAILED
;
1768 asl_msg_release(aux
);
1774 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
);
1775 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
);
1778 if (fileport
== MACH_PORT_NULL
)
1780 asl_msg_release(aux
);
1781 return ASL_STATUS_FAILED
;
1784 fd
= fileport_makefd(fileport
);
1785 mach_port_deallocate(mach_task_self(), fileport
);
1788 asl_msg_release(aux
);
1793 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1805 status
= _asl_aux_save_context(ctx
);
1813 asl_create_auxiliary_file(asl_object_t msg
, const char *title
, const char *uti
, int *out_fd
)
1815 if (out_fd
== NULL
) return -1;
1817 ASL_STATUS status
= _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, NULL
, out_fd
);
1818 return (status
== ASL_STATUS_OK
) ? 0 : -1;
1822 asl_log_auxiliary_location(asl_object_t msg
, const char *title
, const char *uti
, const char *url
)
1824 ASL_STATUS status
= _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, url
, NULL
);
1825 return (status
== ASL_STATUS_OK
) ? 0 : -1;
1829 * Close an auxiliary file.
1830 * Sends the cached auxiliary message to syslogd.
1831 * Returns 0 on success, -1 on error.
1834 asl_close_auxiliary_file(int fd
)
1838 dispatch_semaphore_t aux_sem
= NULL
;
1840 pthread_mutex_lock(&(_asl_global
.lock
));
1845 for (i
= 0; i
< _asl_global
.aux_count
; i
++)
1847 if (_asl_global
.aux_ctx
[i
]->fd
== fd
)
1851 aux_msg
= _asl_global
.aux_ctx
[i
]->msg
;
1852 aux_sem
= _asl_global
.aux_ctx
[i
]->sem
;
1854 free(_asl_global
.aux_ctx
[i
]);
1856 for (j
= i
+ 1; j
< _asl_global
.aux_count
; i
++, j
++)
1858 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
];
1861 _asl_global
.aux_count
--;
1863 if (_asl_global
.aux_count
== 0)
1865 free(_asl_global
.aux_ctx
);
1866 _asl_global
.aux_ctx
= NULL
;
1870 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count
* sizeof(asl_aux_context_t
*));
1871 if (_asl_global
.aux_ctx
== NULL
)
1873 _asl_global
.aux_count
= 0;
1882 pthread_mutex_unlock(&(_asl_global
.lock
));
1886 if (aux_msg
!= NULL
)
1888 uint32_t eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux_msg
, -1);
1889 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status
= -1;
1890 asl_msg_release(aux_msg
);
1893 if (aux_sem
!= NULL
)
1895 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
);
1896 dispatch_release(aux_sem
);
1905 _asl_server_control_query(void)
1907 asl_msg_list_t
*list
= NULL
;
1909 uint32_t len
, reslen
, status
;
1910 uint64_t cmax
, qmin
;
1911 kern_return_t kstatus
;
1913 asl_msg_t
*m
= NULL
;
1914 static const char ctlstr
[] = "1\nQ [= ASLOption control]\n";
1916 _asl_global_init(0);
1917 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1919 len
= strlen(ctlstr
) + 1;
1926 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_ASL
));
1927 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1929 memmove(vmstr
, ctlstr
, len
);
1932 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1933 if (kstatus
!= KERN_SUCCESS
)
1935 /* retry once if the call failed */
1936 _asl_global_init(1);
1937 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1940 list
= asl_msg_list_from_string(res
);
1941 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1943 if (list
== NULL
) return NULL
;
1944 if (list
->count
> 0) m
= asl_msg_retain(list
->msg
[0]);
1945 asl_msg_list_release(list
);
1950 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1953 asl_store_location()
1955 kern_return_t kstatus
;
1957 uint32_t reslen
, status
;
1960 _asl_global_init(0);
1961 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
1966 status
= ASL_STATUS_OK
;
1968 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1969 if (kstatus
!= KERN_SUCCESS
)
1971 /* retry once if the call failed */
1972 _asl_global_init(1);
1973 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1976 /* res should never be returned, but just to be certain we don't leak VM ... */
1977 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1979 if (kstatus
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
;
1980 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
1981 return ASL_STORE_LOCATION_FILE
;
1985 asl_open_path(const char *path
, uint32_t opts
)
1988 asl_file_t
*fout
= NULL
;
1989 asl_store_t
*sout
= NULL
;
1991 if (opts
== 0) opts
= ASL_OPT_OPEN_READ
;
1993 if (opts
& ASL_OPT_OPEN_READ
)
1997 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT
, &sout
) != ASL_STATUS_OK
) return NULL
;
1998 return (asl_object_t
)sout
;
2001 memset(&sb
, 0, sizeof(struct stat
));
2002 if (stat(path
, &sb
) < 0) return NULL
;
2004 if (sb
.st_mode
& S_IFREG
)
2006 if (asl_file_open_read(path
, &fout
) != ASL_STATUS_OK
) return NULL
;
2007 return (asl_object_t
)fout
;
2009 else if (sb
.st_mode
& S_IFDIR
)
2011 if (asl_store_open_read(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
2012 return (asl_object_t
)sout
;
2017 else if (opts
& ASL_OPT_OPEN_WRITE
)
2019 if (path
== NULL
) return NULL
;
2021 memset(&sb
, 0, sizeof(struct stat
));
2022 if (stat(path
, &sb
) < 0)
2024 if (errno
!= ENOENT
) return NULL
;
2026 if (opts
& ASL_OPT_CREATE_STORE
)
2028 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
2029 return (asl_object_t
)sout
;
2033 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
;
2034 return (asl_object_t
)fout
;
2037 else if (sb
.st_mode
& S_IFREG
)
2039 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
;
2040 return (asl_object_t
)fout
;
2042 else if (sb
.st_mode
& S_IFDIR
)
2044 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
2045 return (asl_object_t
)sout
;