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 uint8_t shim_asl_to_trace_type
[8] = { 
  91         OS_TRACE_TYPE_FAULT
, OS_TRACE_TYPE_FAULT
, OS_TRACE_TYPE_FAULT
, // Emergency, Alert, Critical 
  92         OS_TRACE_TYPE_ERROR
, // Error 
  93         OS_TRACE_TYPE_RELEASE
, OS_TRACE_TYPE_RELEASE
, OS_TRACE_TYPE_RELEASE
, // Warning, Notice, Info 
  94         OS_TRACE_TYPE_DEBUG 
// Debug 
  99 static ASL_STATUS 
_asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t 
*msg
, const char *mstring
); 
 100 __private_extern__ asl_client_t 
*_asl_open_default(); 
 103 uint32_t notify_register_plain(const char *name
, int *out_token
); 
 105 /* fork handling in asl_fd.c */ 
 106 extern void _asl_redirect_fork_child(void); 
 112         dispatch_semaphore_t sem
; 
 121         uint64_t proc_filter
; 
 122         uint64_t master_filter
; 
 126         mach_port_t server_port
; 
 128         pthread_mutex_t lock
; 
 130         asl_aux_context_t 
**aux_ctx
; 
 134 __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
}; 
 136 static const char *level_to_number_string
[] = {"0", "1", "2", "3", "4", "5", "6", "7"}; 
 138 #define ASL_SERVICE_NAME "com.apple.system.logger" 
 141  * Called from the child process inside fork() to clean up 
 142  * inherited state from the parent process. 
 144  * NB. A lock isn't required, since we're single threaded in this call. 
 149         _asl_global
.notify_count 
= 0; 
 150         _asl_global
.rc_change_token 
= -1; 
 151         _asl_global
.master_token 
= -1; 
 152         _asl_global
.notify_token 
= -1; 
 153         _asl_global
.quota 
= 0; 
 154         _asl_global
.last_send 
= 0; 
 155         _asl_global
.last_oq_msg 
= 0; 
 157         _asl_global
.server_port 
= MACH_PORT_NULL
; 
 159         pthread_mutex_init(&(_asl_global
.lock
), NULL
); 
 161         _asl_redirect_fork_child(); 
 165  * asl_remote_notify_name: returns the notification key for remote-control filter 
 166  * changes for this process. 
 169 asl_remote_notify_name() 
 171         pid_t pid 
= getpid(); 
 172         uid_t euid 
= geteuid(); 
 175         if (euid 
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
); 
 176         else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
); 
 182 _asl_notify_open(int do_lock
) 
 187         if (do_lock 
!= 0) pthread_mutex_lock(&_asl_global
.lock
); 
 189         _asl_global
.notify_count
++; 
 191         if (_asl_global
.notify_token 
!= -1) 
 193                 if (do_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 194                 return ASL_STATUS_OK
; 
 197         if (_asl_global
.rc_change_token 
== -1) 
 199                 status 
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
); 
 200                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token 
= -1; 
 203         if (_asl_global
.master_token 
== -1) 
 205                 status 
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
); 
 206                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.master_token 
= -1; 
 209         notify_name 
= asl_remote_notify_name(); 
 210         if (notify_name 
!= NULL
) 
 212                 status 
= notify_register_plain(notify_name
, &_asl_global
.notify_token
); 
 214                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token 
= -1; 
 217         if (do_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 219         if (_asl_global
.notify_token 
== -1) return ASL_STATUS_FAILED
; 
 220         return ASL_STATUS_OK
; 
 227         pthread_mutex_lock(&_asl_global
.lock
); 
 229         if (_asl_global
.notify_count 
> 0) _asl_global
.notify_count
--; 
 231         if (_asl_global
.notify_count 
> 0) 
 233                 pthread_mutex_unlock(&_asl_global
.lock
); 
 237         if (_asl_global
.rc_change_token 
>= 0) notify_cancel(_asl_global
.rc_change_token
); 
 238         _asl_global
.rc_change_token 
= -1; 
 240         if (_asl_global
.master_token 
>= 0) notify_cancel(_asl_global
.master_token
); 
 241         _asl_global
.master_token 
= -1; 
 243         if (_asl_global
.notify_token 
>= 0) notify_cancel(_asl_global
.notify_token
); 
 244         _asl_global
.notify_token 
= -1; 
 246         pthread_mutex_unlock(&_asl_global
.lock
); 
 251 _asl_global_init(int reset
) 
 253         _asl_global
.server_port 
= asl_core_get_service_port(reset
); 
 257 #pragma mark asl_client 
 260 asl_open(const char *ident
, const char *facility
, uint32_t opts
) 
 262         asl_client_t 
*asl 
= asl_client_open(ident
, facility
, opts
); 
 263         if (asl 
== NULL
) return NULL
; 
 266         if (!(opts 
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1); 
 268         return (asl_object_t
)asl
; 
 272 asl_open_from_file(int fd
, const char *ident
, const char *facility
) 
 274         return (asl_object_t
)asl_client_open_from_file(fd
, ident
, facility
); 
 278 asl_close(asl_object_t obj
) 
 283 __private_extern__ asl_client_t 
* 
 286         static dispatch_once_t once
; 
 288         dispatch_once(&once
, ^{ 
 290                  * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock 
 291                  * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1) 
 292                  * which locks _asl_global.lock. 
 294                 _asl_global
.asl 
= (asl_client_t 
*)asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); 
 296                 /* Reset options to clear ASL_OPT_NO_REMOTE bit */ 
 297                 if (_asl_global
.asl 
!= NULL
) _asl_global
.asl
->options 
= 0; 
 299                 /* Now call _asl_notify_open(0) to finish the work */ 
 303         return _asl_global
.asl
; 
 307  * asl_add_file: write log messages to the given file descriptor 
 308  * Log messages will be written to this file as well as to the server. 
 311 asl_add_output_file(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
) 
 313         int status
, use_global_lock 
= 0; 
 316         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 318         asl 
= (asl_client_t 
*)client
; 
 321                 asl 
= _asl_open_default(); 
 322                 if (asl 
== NULL
) return -1; 
 323                 pthread_mutex_lock(&_asl_global
.lock
); 
 327         status 
= asl_client_add_output_file(asl
, fd
, mfmt
, tfmt
, filter
, text_encoding
); 
 329         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 330         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 333 /* returns previous filter value or -1 on error */ 
 335 asl_set_output_file_filter(asl_object_t client
, int fd
, int filter
) 
 338         int use_global_lock 
= 0; 
 341         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 343         asl 
= (asl_client_t 
*)client
; 
 346                 asl 
= _asl_open_default(); 
 347                 if (asl 
== NULL
) return -1; 
 348                 pthread_mutex_lock(&_asl_global
.lock
); 
 352         last 
= asl_client_set_output_file_filter(asl
, fd
, filter
); 
 354         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 358 /* SPI - Deprecated */ 
 360 asl_add_output(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
) 
 362         return asl_add_output_file(client
, fd
, mfmt
, tfmt
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), text_encoding
); 
 365 /* SPI - Deprecated */ 
 367 asl_add_log_file(asl_object_t client
, int fd
) 
 369         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
); 
 373  * asl_remove_output: stop writing log messages to the given file descriptor 
 376 asl_remove_output_file(asl_object_t client
, int fd
) 
 378         int status
, use_global_lock 
= 0; 
 381         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 383         asl 
= (asl_client_t 
*)client
; 
 386                 asl 
= _asl_open_default(); 
 387                 if (asl 
== NULL
) return -1; 
 388                 pthread_mutex_lock(&_asl_global
.lock
); 
 392         status 
= asl_client_remove_output_file(asl
, fd
); 
 394         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 395         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 399 asl_remove_output(asl_object_t client
, int fd
) 
 401         return asl_remove_output_file(client
, fd
); 
 405 asl_remove_log_file(asl_object_t client
, int fd
) 
 407         return asl_remove_output_file(client
, fd
); 
 410 /* returns previous filter value or -1 on error */ 
 412 asl_set_filter(asl_object_t client
, int f
) 
 414         int last
, use_global_lock 
= 0; 
 417         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 419         asl 
= (asl_client_t 
*)client
; 
 422                 asl 
= _asl_open_default(); 
 423                 if (asl 
== NULL
) return -1; 
 424                 pthread_mutex_lock(&_asl_global
.lock
); 
 428         last 
= asl_client_set_filter(asl
, f
); 
 430         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 436 #pragma mark message sending 
 439  * Evaluate client / message / level to determine what to do with a message. 
 440  * Checks filters, tunneling, and log files. 
 441  * Returns the bits below, ORed with the message level. 
 443  * EVAL_SEND_ASL        - send this message to syslogd 
 444  * EVAL_SEND_TRACE      - log this message with Activity Tracing 
 445  * EVAL_ASL_FILE        - write to a standalone ASL file (see asl_open_from_file) 
 446  * EVAL_TEXT_FILE       - write this message to a text file / stderr 
 447  * EVAL_TUNNEL          - tunneling enabled when sending to syslogd 
 450 _asl_evaluate_send(asl_object_t client
, asl_object_t m
, int slevel
) 
 453         asl_msg_t 
*msg 
= (asl_msg_t 
*)m
; 
 454         uint32_t level
, lmask
, filter
, status
, tunnel
; 
 460         level 
= ASL_LEVEL_DEBUG
; 
 461         if (slevel 
>= 0) level 
= slevel
; 
 464         if ((asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
) == 0) && (val 
!= NULL
)) level 
= atoi(val
); 
 466         if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 467         else if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 469         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) 
 471                 /* sending to something other than a client */ 
 472                 return EVAL_ACTIVE 
| EVAL_SEND_ASL 
| level
; 
 475         asl 
= (asl_client_t 
*)client
; 
 476         if ((asl 
!= NULL
) && (asl
->aslfile 
!= NULL
)) return (EVAL_ASL_FILE 
| level
); 
 478         if (asl 
== NULL
) asl 
= _asl_open_default(); 
 481                 eval 
= EVAL_ACTIVE 
| EVAL_DEFAULT_ACTION 
| level
; 
 482                 eval 
&= ~EVAL_SEND_ASL
; 
 486         eval 
= (asl_client_get_control(asl
) & EVAL_ACTION_MASK
) | level
; 
 488         filter 
= asl
->filter 
& 0xff; 
 489         tunnel 
= (asl
->filter 
& ASL_FILTER_MASK_TUNNEL
) >> 8; 
 490         if (tunnel 
!= 0) eval 
|= EVAL_TUNNEL
; 
 492         /* don't send MessageTracer messages to Activity Tracing */ 
 494         if ((asl_msg_lookup(msg
, ASL_KEY_MESSAGETRACER
, &val
, NULL
) == 0) && (val 
!= NULL
)) eval 
&= ~EVAL_SEND_TRACE
; 
 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
; 
 555  * Internal routine used by asl_vlog. 
 556  * msg:  an asl messsage 
 557  * eval: log level and send flags for the message 
 558  * format: A formating string 
 559  * ap: va_list for the format 
 560  * returns 0 for success, non-zero for failure 
 562 __private_extern__ ASL_STATUS
 
 563 _asl_lib_vlog(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
) 
 565         int saved_errno 
= errno
; 
 567         char *str
, *fmt
, estr
[NL_TEXTMAX
]; 
 568         uint32_t i
, len
, elen
, expand
; 
 570         if (format 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 572         /* insert strerror for %m */ 
 577         for (i 
= 0; format
[i
] != '\0'; i
++) 
 579                 if (format
[i
] == '%') 
 581                         if (format
[i
+1] == '\0') len
++; 
 582                         else if (format
[i
+1] == 'm') 
 585                                 strerror_r(saved_errno
, estr
, sizeof(estr
)); 
 599         fmt 
= (char *)format
; 
 603                 fmt 
= malloc(len 
+ 1); 
 604                 if (fmt 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 608                 for (i 
= 0; format
[i
] != '\0'; i
++) 
 610                         if (format
[i
] == '%') 
 612                                 if (format
[i
+1] == '\0') 
 615                                 else if ((format
[i
+1] == 'm') && (elen 
!= 0)) 
 617                                         memcpy(fmt
+len
, estr
, elen
); 
 623                                         fmt
[len
++] = format
[i
++]; 
 624                                         fmt
[len
++] = format
[i
]; 
 627                         else fmt
[len
++] = format
[i
]; 
 634         vasprintf(&str
, fmt
, ap
); 
 635         if (expand 
!= 0) free(fmt
); 
 637         if (str 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 639         status 
= _asl_send_message(obj
, eval
, (asl_msg_t 
*)msg
, str
); 
 647  * Similar to asl_log, but take a va_list instead of a list of arguments. 
 648  * msg:  an asl message 
 649  * level: the log level of the associated message 
 650  * format: A formating string 
 651  * ap: va_list for the format 
 652  * returns 0 for success, non-zero for failure 
 655 asl_vlog(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, va_list ap
) 
 657         ASL_STATUS status 
= ASL_STATUS_OK
; 
 658         uint32_t eval 
= _asl_evaluate_send(client
, msg
, level
); 
 660         if (eval 
& EVAL_SEND_TRACE
) 
 663                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 664                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 665                 uint8_t trace_type 
= shim_asl_to_trace_type
[level
]; 
 667                 va_copy(ap_copy
, ap
); 
 668                 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT
, trace_type
, format
, ap_copy
, ^(xpc_object_t xdict
) {_asl_log_args_to_xpc(client
, msg
, xdict
);} ); 
 672         if (os_log_shim_legacy_logging_enabled() && (eval 
& EVAL_ASL
)) 
 674                 asl_msg_t 
*smsg 
= asl_msg_new(ASL_TYPE_MSG
); 
 675                 if (eval 
& EVAL_SEND_TRACE
) asl_msg_set_key_val(smsg
, "ASLSHIM", "1"); 
 676                 smsg 
= asl_msg_merge(smsg
, (asl_msg_t 
*)msg
); 
 678                 status 
= _asl_lib_vlog(client
, eval
, (asl_object_t
)smsg
, format
, ap
); 
 680                 asl_msg_release(smsg
); 
 683         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 688  * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and 
 689  * forwards the call to _asl_lib_vlog. 
 690  * msg:  an asl message 
 691  * eval: log level and send flags for the message 
 692  * format: A formating string 
 693  * ... args for format 
 694  * returns 0 for success, non-zero for failure 
 697 _asl_lib_log(asl_object_t client
, uint32_t eval
, asl_object_t msg
, const char *format
, ...) 
 705                 va_start(ap
, format
); 
 706                 status 
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
); 
 715  * Processes an ASL log message. 
 716  * msg:  an asl message 
 717  * level: the log level of the associated message 
 718  * format: A formating string 
 719  * ... args for format 
 720  * returns 0 for success, non-zero for failure 
 723 asl_log(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, ...) 
 725         ASL_STATUS status 
= ASL_STATUS_OK
; 
 726         uint32_t eval 
= _asl_evaluate_send(client
, msg
, level
); 
 728         if (eval 
& EVAL_SEND_TRACE
) 
 731                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 732                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 733                 uint8_t trace_type 
= shim_asl_to_trace_type
[level
]; 
 735                 va_start(ap
, format
); 
 736                 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT
, trace_type
, format
, ap
, ^(xpc_object_t xdict
) {_asl_log_args_to_xpc(client
, msg
, xdict
);} ); 
 740         if (os_log_shim_legacy_logging_enabled() && (eval 
& EVAL_ASL
)) 
 743                 asl_msg_t 
*smsg 
= asl_msg_new(ASL_TYPE_MSG
); 
 744                 if (eval 
& EVAL_SEND_TRACE
) asl_msg_set_key_val(smsg
, "ASLSHIM", "1"); 
 745                 smsg 
= asl_msg_merge(smsg
, (asl_msg_t 
*)msg
); 
 747                 va_start(ap
, format
); 
 748                 status 
= _asl_lib_vlog(client
, eval
, (asl_object_t
)smsg
, format
, ap
); 
 751                 asl_msg_release(smsg
); 
 754         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 759  * Like asl_log, supplies NULL client and msg. 
 760  * level: the log level of the associated message 
 761  * format: A formating string 
 762  * ... args for format 
 763  * returns 0 for success, non-zero for failure 
 766 asl_log_message(int level
, const char *format
, ...) 
 768         ASL_STATUS status 
= ASL_STATUS_OK
; 
 769         uint32_t eval 
= _asl_evaluate_send(NULL
, NULL
, level
); 
 771         if (eval 
& EVAL_SEND_TRACE
) 
 774                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 775                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 776                 uint8_t trace_type 
= shim_asl_to_trace_type
[level
]; 
 778                 va_start(ap
, format
); 
 779                 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT
, trace_type
, format
, ap
, NULL
); 
 783         if (os_log_shim_legacy_logging_enabled() && (eval 
& EVAL_ASL
)) 
 786                 asl_msg_t 
*smsg 
= asl_msg_new(ASL_TYPE_MSG
); 
 787                 if (eval 
& EVAL_SEND_TRACE
) asl_msg_set_key_val(smsg
, "ASLSHIM", "1"); 
 789                 va_start(ap
, format
); 
 790                 status 
= _asl_lib_vlog(NULL
, eval
, (asl_object_t
)smsg
, format
, ap
); 
 793                 asl_msg_release(smsg
); 
 796         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 800  * asl_get_filter: gets the values for the local, master, and remote filters,  
 801  * and indicates which one is active. 
 804 asl_get_filter(asl_object_t client
, int *local
, int *master
, int *remote
, int *active
) 
 806         asl_client_t 
*asl
, *asl_default
; 
 811         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 818         asl_default 
= _asl_open_default(); 
 820         asl 
= (asl_client_t 
*)client
; 
 821         if (asl 
== NULL
) asl 
= asl_default
; 
 822         if (asl 
!= NULL
) l 
= asl
->filter 
& EVAL_LEVEL_MASK
; 
 824         if ((asl_default 
!= NULL
) && (!(asl_default
->options 
& ASL_OPT_NO_REMOTE
))) 
 826                 pthread_mutex_lock(&_asl_global
.lock
); 
 828                 if (_asl_global
.rc_change_token 
>= 0) 
 830                         /* initialize or re-check process-specific and master filters  */ 
 832                         status 
= notify_check(_asl_global
.rc_change_token
, &check
); 
 833                         if ((status 
== NOTIFY_STATUS_OK
) && (check 
!= 0)) 
 835                                 if (_asl_global
.master_token 
>= 0) 
 838                                         status 
= notify_get_state(_asl_global
.master_token
, &v64
); 
 839                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.master_filter 
= v64
; 
 842                                 if (_asl_global
.notify_token 
>= 0) 
 845                                         status 
= notify_get_state(_asl_global
.notify_token
, &v64
); 
 846                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter 
= v64
; 
 851                 m 
= _asl_global
.master_filter
; 
 854                 r 
= _asl_global
.proc_filter
; 
 857                 pthread_mutex_unlock(&_asl_global
.lock
); 
 860         if (local 
!= NULL
) *local 
= l
; 
 861         if (master 
!= NULL
) *master 
= m
; 
 862         if (remote 
!= NULL
) *remote 
= r
; 
 863         if (active 
!= NULL
) *active 
= x
; 
 868 /* SPI for SHIM control */ 
 870 asl_set_local_control(asl_object_t client
, uint32_t filter
) 
 872         asl_client_t 
*asl 
= (asl_client_t 
*)client
; 
 875                 asl 
= _asl_open_default(); 
 876                 if (asl 
== NULL
) return UINT32_MAX
; 
 878         else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
; 
 880         return asl_client_set_control(asl
, filter
); 
 884 asl_get_local_control(asl_object_t client
) 
 886         asl_client_t 
*asl 
= (asl_client_t 
*)client
; 
 889                 asl 
= _asl_open_default(); 
 890                 if (asl 
== NULL
) return UINT32_MAX
; 
 892         else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
; 
 894         return asl_client_get_control(asl
); 
 898  * Sets PID and OSActivityID values in a new message. 
 899  * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided. 
 902 asl_base_msg(asl_client_t 
*asl
, uint32_t level
, const struct timeval 
*tv
, const char *sstr
, const char *fstr
, const char *mstr
) 
 907         unsigned int osacount 
= 1; 
 908         os_activity_t osaid 
= 0; 
 910         aux 
= asl_msg_new(ASL_TYPE_MSG
); 
 911         if (aux 
== NULL
) return NULL
; 
 914         if (level 
<= 7) asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, level_to_number_string
[level
]); 
 916         /* Time and TimeNanoSec */ 
 919                 snprintf(aux_val
, sizeof(aux_val
), "%llu", (unsigned long long) tv
->tv_sec
); 
 920                 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
); 
 922                 snprintf(aux_val
, sizeof(aux_val
), "%d", tv
->tv_usec 
* 1000); 
 923                 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
); 
 927         if (mstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstr
); 
 930         snprintf(aux_val
, sizeof(aux_val
), "%u", getpid()); 
 931         asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
); 
 934         if (os_activity_get_active(&osaid
, &osacount
) == 1) 
 936                 snprintf(aux_val
, sizeof(aux_val
), "0x%016llx", (uint64_t)osaid
); 
 937                 asl_msg_set_key_val(aux
, ASL_KEY_OS_ACTIVITY_ID
, aux_val
); 
 941         if ((sstr 
== NULL
) && (asl 
!= NULL
)) 
 943                 /* See if the client has a value for ASL_KEY_SENDER */ 
 944                 status 
= asl_msg_lookup((asl_msg_t 
*)asl
->kvdict
, ASL_KEY_SENDER
, &sstr
, NULL
); 
 945                 if ((status 
!= 0) || (sstr 
== NULL
)) 
 949                         /* See if the global cache has a value for ASL_KEY_SENDER */ 
 950                         if (_asl_global
.sender 
== NULL
) 
 952                                 /* Get the process name with _NSGetArgv */ 
 953                                 char *name 
= *(*_NSGetArgv()); 
 956                                         char *x 
= strrchr(name
, '/'); 
 960                                         /* Set the cache value */ 
 961                                         pthread_mutex_lock(&_asl_global
.lock
); 
 962                                         if (_asl_global
.sender 
== NULL
) _asl_global
.sender 
= strdup(x
); 
 963                                         pthread_mutex_unlock(&_asl_global
.lock
); 
 967                         if (_asl_global
.sender 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
); 
 968                         else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown"); 
 972         if (sstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, sstr
); 
 975         if ((fstr 
== NULL
) && (asl 
!= NULL
)) 
 977                 status 
= asl_msg_lookup((asl_msg_t 
*)asl
->kvdict
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
 978                 if (status 
!= 0) fstr 
= NULL
; 
 981         if (fstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, fstr
); 
 988  * Possibly useful someday... 
 991 asl_prepared_message(asl_client_t 
*asl
, asl_msg_t 
*msg
) 
 993         uint32_t i
, len
, level
, outstatus
; 
 994         const char *val
, *sstr
, *fstr
; 
 995         struct timeval tval 
= {0, 0}; 
1001                 asl 
= _asl_open_default(); 
1002                 if (asl 
== NULL
) return NULL
; 
1005         status 
= gettimeofday(&tval
, NULL
); 
1008                 time_t tick 
= time(NULL
); 
1014         status 
= asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
); 
1015         if (status 
!= 0) val 
= NULL
; 
1017         level 
= ASL_LEVEL_DEBUG
; 
1018         if (val 
!= NULL
) level 
= atoi(val
); 
1019         if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
1022         status 
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1023         if (status 
!= 0) sstr 
= NULL
; 
1026         status 
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1027         if (status 
!= 0) fstr 
= NULL
; 
1029         out 
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, NULL
); 
1030         out 
= asl_msg_merge(out
, msg
); 
1037 _asl_set_option(asl_msg_t 
*msg
, const char *opt
) 
1039         const char *val 
= NULL
; 
1042         if (msg 
== NULL
) return; 
1043         if (opt 
== NULL
) return; 
1045         status 
= asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
); 
1046         if ((status 
!= 0) || (val 
== NULL
)) 
1048                 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, opt
); 
1052                 char *option 
= NULL
; 
1053                 asprintf(&option
, "%s %s", opt
, val
); 
1054                 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, option
); 
1060 _asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t 
*msg
, const char *mstr
) 
1062         uint32_t i
, len
, level
, lmask
, outstatus
, objtype
; 
1063         const char *sstr
, *fstr
; 
1064         struct timeval tval 
= {0, 0}; 
1066         int use_global_lock 
= 0; 
1067         kern_return_t kstatus
; 
1069         asl_msg_t 
*qd_msg 
= NULL
; 
1070         asl_client_t 
*asl 
= NULL
; 
1071         static dispatch_once_t noquota_once
; 
1073         if ((eval 
& EVAL_ASL
) == 0) return ASL_STATUS_OK
; 
1077                 asl 
= _asl_open_default(); 
1078                 if (asl 
== NULL
) return ASL_STATUS_FAILED
; 
1079                 use_global_lock 
= 1; 
1080                 objtype 
= ASL_TYPE_CLIENT
; 
1084                 objtype 
= asl_get_type(obj
); 
1085                 if (objtype 
== ASL_TYPE_CLIENT
) asl 
= (asl_client_t 
*)obj
; 
1088         level 
= eval 
& EVAL_LEVEL_MASK
; 
1089         if (level 
> 7) level 
= 7; 
1090         lmask 
= ASL_FILTER_MASK(level
); 
1092         if ((objtype 
== ASL_TYPE_CLIENT
) && (asl
->aslfile 
!= NULL
)) use_global_lock 
= 1; 
1094         status 
= gettimeofday(&tval
, NULL
); 
1097                 time_t tick 
= time(NULL
); 
1103         status 
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1104         if (status 
!= 0) sstr 
= NULL
; 
1107         status 
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1108         if (status 
!= 0) fstr 
= NULL
; 
1110         sendmsg 
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
); 
1111         if (sendmsg 
== NULL
) return ASL_STATUS_FAILED
; 
1113         /* Set "ASLOption store" if tunneling */ 
1114         if (eval 
& EVAL_TUNNEL
) _asl_set_option(sendmsg
, ASL_OPT_STORE
); 
1118         if (use_global_lock 
!= 0) pthread_mutex_lock(&_asl_global
.lock
); 
1120         sendmsg 
= asl_msg_merge(sendmsg
, msg
); 
1122         if (objtype 
!= ASL_TYPE_CLIENT
) 
1124                 asl_append(obj
, (asl_object_t
)sendmsg
); 
1125                 asl_msg_release(sendmsg
); 
1126                 if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1127                 return ASL_STATUS_OK
; 
1131          * If there is an aslfile this is a stand-alone file client. 
1132          * Just save to the file. 
1134         if (asl
->aslfile 
!= NULL
) 
1136                 outstatus 
= ASL_STATUS_FAILED
; 
1138                 if (sendmsg 
!= NULL
) 
1140                         outstatus 
= asl_file_save(asl
->aslfile
, sendmsg
, &(asl
->aslfileid
)); 
1144                 asl_msg_release(sendmsg
); 
1146                 if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1150         _asl_global_init(0); 
1155          * Quotas are disabled if: 
1156          * - a remote control filter is in place (EVAL_TUNNEL) 
1157          * - Environment variable ASL_QUOTA_DISABLED == 1 
1158          * - /etc/asl/.noquota existed at the time that the process started 
1160          * We just check /etc/asl/.noquota once, since it would be 
1161          * expensive to stat() for every log message. 
1163          * We only check the Environment variable once, since getenv() is 
1164          * not thread safe.  If someone is changing the environment, 
1168         dispatch_once(&noquota_once
, ^{ 
1170                 memset(&sb
, 0, sizeof(struct stat
)); 
1172                 int save_errno 
= errno
; 
1174                 if (stat(NOQUOTA_FILE_PATH
, &sb
) == 0) 
1176                         _asl_global
.quota 
= UINT32_MAX
; 
1180                         const char *qtest 
= getenv(NOQUOTA_ENV
); 
1181                         if ((qtest 
!= NULL
) && (!strcmp(qtest
, "1"))) _asl_global
.quota 
= UINT32_MAX
; 
1184                 /* reset errno since we want stat() to fail silently */ 
1188         if (((eval 
& EVAL_TUNNEL
) == 0) && (_asl_global
.quota 
!= UINT32_MAX
)) 
1190                 time_t last_send 
= _asl_global
.last_send
; 
1191                 time_t last_oq 
= _asl_global
.last_oq_msg
; 
1192                 uint32_t qcurr 
= _asl_global
.quota
; 
1194                 uint32_t qinc
, qnew
; 
1198                 /* add QUOTA_MPS to quota for each second we've been idle */ 
1199                 if (tval
.tv_sec 
> last_send
) 
1201                         delta 
= tval
.tv_sec 
- last_send
; 
1204                         if (delta 
< (QUOTA_MPH 
/ QUOTA_MPS
)) qinc 
= delta 
* QUOTA_MPS
; 
1206                         qnew 
= MIN(QUOTA_MPH
, qcurr 
+ qinc
); 
1207                         OSAtomicCompareAndSwapLongBarrier(last_send
, tval
.tv_sec
, (long *)&_asl_global
.last_send
); 
1212                         if ((tval
.tv_sec 
- last_oq
) > QUOTA_MSG_INTERVAL
) 
1215                                 OSAtomicCompareAndSwapLongBarrier(last_oq
, tval
.tv_sec
, (long *)&_asl_global
.last_oq_msg
); 
1219                                 eval 
&= ~EVAL_SEND_ASL
; 
1224                         OSAtomicCompareAndSwap32Barrier(qcurr
, qnew 
- 1, (int32_t *)&_asl_global
.quota
); 
1228         if ((_asl_global
.server_port 
!= MACH_PORT_NULL
) && (eval 
& EVAL_SEND_ASL
)) 
1230                 asl_string_t 
*send_str
; 
1234                 if (eval 
& EVAL_QUOTA
) 
1236                         asl_msg_set_key_val(sendmsg
, ASL_KEY_LEVEL
, QUOTA_LEVEL_STR
); 
1237                         asl_msg_set_key_val(sendmsg
, ASL_KEY_MSG
, QUOTA_MSG
); 
1242                         send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, qd_msg
, "raw"); 
1243                         len 
= asl_string_length(send_str
); 
1244                         vmsize 
= asl_string_allocated_size(send_str
); 
1245                         str 
= asl_string_release_return_bytes(send_str
); 
1246                         if (len 
!= 0) kstatus 
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
); 
1247                         if ((str 
!= NULL
) && (vmsize 
!= 0)) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1248                         asl_msg_release(qd_msg
); 
1251                 send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, sendmsg
, "raw"); 
1252                 len 
= asl_string_length(send_str
); 
1254                 if (len 
> LIBASL_MAX_MSG_SIZE
) 
1258                         snprintf(tmp
, sizeof(tmp
), SIZE_LIMIT_MSG
, len
, LIBASL_MAX_MSG_SIZE
); 
1259                         asl_msg_t 
*limitmsg 
= asl_base_msg(asl
, ASL_LEVEL_CRIT
, &tval
, sstr
, fstr
, tmp
); 
1261                         asl_string_release(send_str
); 
1264                         if (limitmsg 
!= NULL
) 
1266                                 /* Set "ASLOption store" if tunneling */ 
1267                                 if (eval 
& EVAL_TUNNEL
) _asl_set_option(limitmsg
, ASL_OPT_STORE
); 
1269                                 send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, limitmsg
, "raw"); 
1270                                 len 
= asl_string_length(send_str
); 
1271                                 asl_msg_release(limitmsg
); 
1275                 vmsize 
= asl_string_allocated_size(send_str
); 
1276                 str 
= asl_string_release_return_bytes(send_str
); 
1280                         /* send a mach message to syslogd */ 
1281                         kstatus 
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
); 
1282                         if (kstatus 
!= KERN_SUCCESS
) 
1284                                 /* retry once if the call failed */ 
1285                                 _asl_global_init(1); 
1286                                 kstatus 
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
); 
1287                                 if (kstatus 
!= KERN_SUCCESS
) 
1289                                         vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1294                 else if (vmsize 
>0) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1297         if ((sendmsg 
!= NULL
) && (asl
->out_count 
> 0)) 
1299                 /* write to file descriptors */ 
1300                 for (i 
= 0; i 
< asl
->out_count
; i
++) 
1302                         if ((asl
->out_list
[i
].fd 
>= 0) && (asl
->out_list
[i
].filter 
!= 0) && ((asl
->out_list
[i
].filter 
& lmask
) != 0)) 
1307                                 str 
= asl_format_message(sendmsg
, asl
->out_list
[i
].mfmt
, asl
->out_list
[i
].tfmt
, asl
->out_list
[i
].encoding
, &len
); 
1308                                 if (str 
== NULL
) continue; 
1310                                 status 
= write(asl
->out_list
[i
].fd
, str
, len 
- 1); 
1313                                         /* soft error for fd 2 (stderr) */ 
1314                                         if (asl
->out_list
[i
].fd 
!= 2) outstatus 
= -1; 
1315                                         asl
->out_list
[i
].fd 
= -1; 
1323         asl_msg_release(sendmsg
); 
1325         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1331  * asl_send: send a message  
1332  * This routine may be used instead of asl_log() or asl_vlog() if asl_set() 
1333  * has been used to set all of a message's attributes. 
1334  * eval:  hints about what to do with the message 
1335  * msg:  an asl message 
1336  * returns 0 for success, non-zero for failure 
1338 __private_extern__ ASL_STATUS
 
1339 asl_client_internal_send(asl_object_t obj
, asl_object_t msg
) 
1341         int status 
= ASL_STATUS_OK
; 
1342         uint32_t eval 
= _asl_evaluate_send(obj
, msg
, -1); 
1343         if (eval 
!= 0) status 
= _asl_send_message(obj
, eval
, (asl_msg_t 
*)msg
, NULL
); 
1349 #pragma mark auxiliary files and URLs 
1352 _asl_aux_save_context(asl_aux_context_t 
*ctx
) 
1354         if (ctx 
== NULL
) return ASL_STATUS_FAILED
; 
1356         pthread_mutex_lock(&_asl_global
.lock
); 
1358         _asl_global
.aux_ctx 
= (asl_aux_context_t 
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count 
+ 1) * sizeof(asl_aux_context_t 
*)); 
1359         if (_asl_global
.aux_ctx 
== NULL
) 
1361                 _asl_global
.aux_count 
= 0; 
1362                 pthread_mutex_unlock(&_asl_global
.lock
); 
1363                 return ASL_STATUS_FAILED
; 
1366         _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
; 
1368         pthread_mutex_unlock(&_asl_global
.lock
); 
1370         return ASL_STATUS_OK
; 
1374  * Creates an auxiliary file that may be used to save arbitrary data.  The ASL message msg 
1375  * will be saved at the time that the auxiliary file is created.  The message will include 
1376  * any keys and values found in msg, and it will include the title and Uniform Type 
1377  * Identifier specified.  Output parameter out_fd will contain the file descriptor of the 
1378  * new auxiliary file. 
1381 _asl_auxiliary(asl_msg_t 
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
) 
1384         asl_string_t 
*send_str
; 
1386         fileport_t fileport
; 
1387         kern_return_t kstatus
; 
1389         uint32_t newurllen
, where
; 
1390         int status
, fd
, fdpair
[2]; 
1392         dispatch_queue_t pipe_q
; 
1393         dispatch_io_t pipe_channel
; 
1394         dispatch_semaphore_t sem
; 
1396         aux 
= asl_msg_new(ASL_TYPE_MSG
); 
1398         if (url 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
); 
1399         if (title 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
); 
1400         if (uti 
== NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data"); 
1401         else asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
); 
1403         aux 
= asl_msg_merge(aux
, msg
); 
1405         /* if (out_fd == NULL), this is from asl_log_auxiliary_location */ 
1408                 uint32_t eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1); 
1409                 status 
= _asl_send_message(NULL
, eval
, aux
, NULL
); 
1410                 asl_msg_release(aux
); 
1414         where 
= asl_store_location(); 
1415         if (where 
== ASL_STORE_LOCATION_MEMORY
) 
1418                 asl_aux_context_t 
*ctx 
= (asl_aux_context_t 
*)calloc(1, sizeof(asl_aux_context_t
)); 
1419                 if (ctx 
== NULL
) return ASL_STATUS_FAILED
; 
1421                 status 
= pipe(fdpair
); 
1425                         return ASL_STATUS_FAILED
; 
1428                 /* give read end to dispatch_io_read */ 
1430                 sem 
= dispatch_semaphore_create(0); 
1432                 ctx
->fd 
= fdpair
[1]; 
1434                 status 
= _asl_aux_save_context(ctx
); 
1435                 if (status 
!= ASL_STATUS_OK
) 
1439                         dispatch_release(sem
); 
1441                         return ASL_STATUS_FAILED
; 
1444                 pipe_q 
= dispatch_queue_create("ASL_AUX_PIPE_Q", NULL
); 
1445                 pipe_channel 
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){ 
1449                 *out_fd 
= fdpair
[1]; 
1451                 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
); 
1453                 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){ 
1456                                 size_t len 
= dispatch_data_get_size(pipedata
); 
1459                                         const char *bytes 
= NULL
; 
1463                                         dispatch_data_t md 
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
); 
1464                                         encoded 
= asl_core_encode_buffer(bytes
, len
); 
1465                                         asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
); 
1467                                         eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1); 
1468                                         _asl_send_message(NULL
, eval
, aux
, NULL
); 
1469                                         asl_msg_release(aux
); 
1470                                         dispatch_release(md
); 
1476                                 dispatch_semaphore_signal(sem
); 
1477                                 dispatch_release(pipe_channel
); 
1478                                 dispatch_release(pipe_q
); 
1482                 return ASL_STATUS_OK
; 
1485         _asl_global_init(0); 
1486         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return ASL_STATUS_FAILED
; 
1488         send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw"); 
1489         len 
= asl_string_length(send_str
); 
1490         vmsize 
= asl_string_allocated_size(send_str
); 
1491         str 
= asl_string_release_return_bytes(send_str
); 
1495                 asl_msg_release(aux
); 
1496                 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1497                 return ASL_STATUS_FAILED
; 
1501         fileport 
= MACH_PORT_NULL
; 
1502         status 
= KERN_SUCCESS
; 
1504         kstatus 
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
); 
1505         if (kstatus 
!= KERN_SUCCESS
) 
1507                 /* retry once if the call failed */ 
1508                 _asl_global_init(1); 
1509                 kstatus 
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
); 
1510                 if (kstatus 
!= KERN_SUCCESS
) 
1512                         vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1513                         asl_msg_release(aux
); 
1514                         return ASL_STATUS_FAILED
; 
1520                 asl_msg_release(aux
); 
1526                 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
); 
1527                 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
); 
1530         if (fileport 
== MACH_PORT_NULL
) 
1532                 asl_msg_release(aux
); 
1533                 return ASL_STATUS_FAILED
; 
1536         fd 
= fileport_makefd(fileport
); 
1537         mach_port_deallocate(mach_task_self(), fileport
); 
1540                 asl_msg_release(aux
); 
1545                 asl_aux_context_t 
*ctx 
= (asl_aux_context_t 
*)calloc(1, sizeof(asl_aux_context_t
)); 
1557                         status 
= _asl_aux_save_context(ctx
); 
1565 asl_create_auxiliary_file(asl_object_t msg
, const char *title
, const char *uti
, int *out_fd
) 
1567         if (out_fd 
== NULL
) return -1; 
1569         ASL_STATUS status 
= _asl_auxiliary((asl_msg_t 
*)msg
, title
, uti
, NULL
, out_fd
); 
1570         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
1574 asl_log_auxiliary_location(asl_object_t msg
, const char *title
, const char *uti
, const char *url
) 
1576         ASL_STATUS status 
= _asl_auxiliary((asl_msg_t 
*)msg
, title
, uti
, url
, NULL
); 
1577         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
1581  * Close an auxiliary file. 
1582  * Sends the cached auxiliary message to syslogd. 
1583  * Returns 0 on success, -1 on error. 
1586 asl_close_auxiliary_file(int fd
) 
1590         dispatch_semaphore_t aux_sem 
= NULL
; 
1592         pthread_mutex_lock(&(_asl_global
.lock
)); 
1597         for (i 
= 0; i 
< _asl_global
.aux_count
; i
++) 
1599                 if (_asl_global
.aux_ctx
[i
]->fd 
== fd
) 
1603                         aux_msg 
= _asl_global
.aux_ctx
[i
]->msg
; 
1604                         aux_sem 
= _asl_global
.aux_ctx
[i
]->sem
; 
1606                         free(_asl_global
.aux_ctx
[i
]); 
1608                         for (j 
= i 
+ 1; j 
< _asl_global
.aux_count
; i
++, j
++) 
1610                                 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
]; 
1613                         _asl_global
.aux_count
--; 
1615                         if (_asl_global
.aux_count 
== 0) 
1617                                 free(_asl_global
.aux_ctx
); 
1618                                 _asl_global
.aux_ctx 
= NULL
; 
1622                                 _asl_global
.aux_ctx 
= (asl_aux_context_t 
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count 
* sizeof(asl_aux_context_t 
*)); 
1623                                 if (_asl_global
.aux_ctx 
== NULL
) 
1625                                         _asl_global
.aux_count 
= 0; 
1634         pthread_mutex_unlock(&(_asl_global
.lock
)); 
1638         if (aux_msg 
!= NULL
) 
1640                 uint32_t eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux_msg
, -1); 
1641                 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status 
= -1; 
1642                 asl_msg_release(aux_msg
); 
1645         if (aux_sem 
!= NULL
) 
1647                 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
); 
1648                 dispatch_release(aux_sem
); 
1657 _asl_server_control_query(void) 
1659         asl_msg_list_t 
*list 
= NULL
; 
1661         uint32_t len
, reslen
, status
; 
1662         uint64_t cmax
, qmin
; 
1663         kern_return_t kstatus
; 
1665         asl_msg_t 
*m 
= NULL
; 
1666         static const char ctlstr
[] = "1\nQ [= ASLOption control]\n"; 
1668         _asl_global_init(0); 
1669         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return NULL
; 
1671         len 
= strlen(ctlstr
) + 1; 
1678         kstatus 
= vm_allocate(mach_task_self(), (vm_address_t 
*)&vmstr
, len
, VM_FLAGS_ANYWHERE 
| VM_MAKE_TAG(VM_MEMORY_ASL
)); 
1679         if (kstatus 
!= KERN_SUCCESS
) return NULL
; 
1681         memmove(vmstr
, ctlstr
, len
); 
1684         kstatus 
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1685         if (kstatus 
!= KERN_SUCCESS
) 
1687                 /* retry once if the call failed */ 
1688                 _asl_global_init(1); 
1689                 kstatus 
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1692         list 
= asl_msg_list_from_string(res
); 
1693         vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
); 
1695         if (list 
== NULL
) return NULL
; 
1696         if (list
->count 
> 0) m 
= asl_msg_retain(list
->msg
[0]); 
1697         asl_msg_list_release(list
); 
1702  * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY 
1705 asl_store_location() 
1707         kern_return_t kstatus
; 
1709         uint32_t reslen
, status
; 
1712         _asl_global_init(0); 
1713         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
; 
1718         status 
= ASL_STATUS_OK
; 
1720         kstatus 
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1721         if (kstatus 
!= KERN_SUCCESS
) 
1723                 /* retry once if the call failed */ 
1724                 _asl_global_init(1); 
1725                 kstatus 
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1728         /* res should never be returned, but just to be certain we don't leak VM ... */ 
1729         if (res 
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
); 
1731         if (kstatus 
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
; 
1732         if (status 
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
; 
1733         return ASL_STORE_LOCATION_FILE
; 
1737 asl_open_path(const char *path
, uint32_t opts
) 
1740         asl_file_t 
*fout 
= NULL
; 
1741         asl_store_t 
*sout 
= NULL
; 
1743         if (opts 
== 0) opts 
= ASL_OPT_OPEN_READ
; 
1745         if (opts 
& ASL_OPT_OPEN_READ
) 
1749                         if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT
, &sout
) != ASL_STATUS_OK
) return NULL
; 
1750                         return (asl_object_t
)sout
; 
1753                 memset(&sb
, 0, sizeof(struct stat
)); 
1754                 if (stat(path
, &sb
) < 0) return NULL
; 
1756                 if (sb
.st_mode 
& S_IFREG
) 
1758                         if (asl_file_open_read(path
, &fout
) != ASL_STATUS_OK
) return NULL
; 
1759                         return (asl_object_t
)fout
; 
1761                 else if (sb
.st_mode 
& S_IFDIR
) 
1763                         if (asl_store_open_read(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
1764                         return (asl_object_t
)sout
; 
1769         else if (opts 
& ASL_OPT_OPEN_WRITE
) 
1771                 if (path 
== NULL
) return NULL
; 
1773                 memset(&sb
, 0, sizeof(struct stat
)); 
1774                 if (stat(path
, &sb
) < 0) 
1776                         if (errno 
!= ENOENT
) return NULL
; 
1778                         if (opts 
& ASL_OPT_CREATE_STORE
) 
1780                                 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
1781                                 return (asl_object_t
)sout
; 
1785                                 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
; 
1786                                 return (asl_object_t
)fout
; 
1789                 else if (sb
.st_mode 
& S_IFREG
) 
1791                         if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
; 
1792                         return (asl_object_t
)fout
; 
1794                 else if (sb
.st_mode 
& S_IFDIR
) 
1796                         if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
1797                         return (asl_object_t
)sout
;