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); 
 113 extern void _asl_mt_shim_fork_child(void); 
 114 extern void _asl_mt_shim_send_message(asl_msg_t 
*msg
); 
 121         dispatch_semaphore_t sem
; 
 130         uint64_t proc_filter
; 
 131         uint64_t master_filter
; 
 135         dispatch_once_t port_lookup_once
; 
 136         mach_port_t server_port
; 
 138         pthread_mutex_t lock
; 
 140         asl_aux_context_t 
**aux_ctx
; 
 144 __private_extern__ _asl_global_t _asl_global 
= {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, 0, MACH_PORT_NULL
, NULL
, PTHREAD_MUTEX_INITIALIZER
, 0, NULL
, NULL
}; 
 146 static const char *level_to_number_string
[] = {"0", "1", "2", "3", "4", "5", "6", "7"}; 
 148 #define ASL_SERVICE_NAME "com.apple.system.logger" 
 151  * Called from the child process inside fork() to clean up 
 152  * inherited state from the parent process. 
 154  * NB. A lock isn't required, since we're single threaded in this call. 
 159         _asl_global
.notify_count 
= 0; 
 160         _asl_global
.rc_change_token 
= -1; 
 161         _asl_global
.master_token 
= -1; 
 162         _asl_global
.notify_token 
= -1; 
 163         _asl_global
.quota 
= 0; 
 164         _asl_global
.last_send 
= 0; 
 165         _asl_global
.last_oq_msg 
= 0; 
 167         _asl_global
.port_lookup_once 
= 0; 
 168         _asl_global
.server_port 
= MACH_PORT_NULL
; 
 170         pthread_mutex_init(&(_asl_global
.lock
), NULL
); 
 172         _asl_redirect_fork_child(); 
 174         _asl_mt_shim_fork_child(); 
 179  * asl_remote_notify_name: returns the notification key for remote-control filter 
 180  * changes for this process. 
 183 asl_remote_notify_name() 
 185         pid_t pid 
= getpid(); 
 186         uid_t euid 
= geteuid(); 
 189         if (euid 
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
); 
 190         else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
); 
 196 _asl_notify_open(int do_lock
) 
 201         if (do_lock 
!= 0) pthread_mutex_lock(&_asl_global
.lock
); 
 203         _asl_global
.notify_count
++; 
 205         if (_asl_global
.notify_token 
!= -1) 
 207                 if (do_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 208                 return ASL_STATUS_OK
; 
 211         if (_asl_global
.rc_change_token 
== -1) 
 213                 status 
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
); 
 214                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token 
= -1; 
 217         if (_asl_global
.master_token 
== -1) 
 219                 status 
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
); 
 220                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.master_token 
= -1; 
 223         notify_name 
= asl_remote_notify_name(); 
 224         if (notify_name 
!= NULL
) 
 226                 status 
= notify_register_plain(notify_name
, &_asl_global
.notify_token
); 
 228                 if (status 
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token 
= -1; 
 231         if (do_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 233         if (_asl_global
.notify_token 
== -1) return ASL_STATUS_FAILED
; 
 234         return ASL_STATUS_OK
; 
 241         pthread_mutex_lock(&_asl_global
.lock
); 
 243         if (_asl_global
.notify_count 
> 0) _asl_global
.notify_count
--; 
 245         if (_asl_global
.notify_count 
> 0) 
 247                 pthread_mutex_unlock(&_asl_global
.lock
); 
 251         if (_asl_global
.rc_change_token 
>= 0) notify_cancel(_asl_global
.rc_change_token
); 
 252         _asl_global
.rc_change_token 
= -1; 
 254         if (_asl_global
.master_token 
>= 0) notify_cancel(_asl_global
.master_token
); 
 255         _asl_global
.master_token 
= -1; 
 257         if (_asl_global
.notify_token 
>= 0) notify_cancel(_asl_global
.notify_token
); 
 258         _asl_global
.notify_token 
= -1; 
 260         pthread_mutex_unlock(&_asl_global
.lock
); 
 267         dispatch_once(&_asl_global
.port_lookup_once
, ^{ 
 268                 char *str 
= getenv("ASL_DISABLE"); 
 269                 if ((str 
== NULL
) || strcmp(str
, "1")) 
 271                         bootstrap_look_up2(bootstrap_port
, ASL_SERVICE_NAME
, &_asl_global
.server_port
, 0, BOOTSTRAP_PRIVILEGED_SERVER
); 
 277 asl_core_get_service_port(__unused 
int reset
) 
 280         return _asl_global
.server_port
; 
 284 #pragma mark asl_client 
 287 asl_open(const char *ident
, const char *facility
, uint32_t opts
) 
 289         asl_client_t 
*asl 
= asl_client_open(ident
, facility
, opts
); 
 290         if (asl 
== NULL
) return NULL
; 
 292         if (!(opts 
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1); 
 294         return (asl_object_t
)asl
; 
 298 asl_open_from_file(int fd
, const char *ident
, const char *facility
) 
 300         return (asl_object_t
)asl_client_open_from_file(fd
, ident
, facility
); 
 304 asl_close(asl_object_t obj
) 
 309 __private_extern__ asl_client_t 
* 
 312         static dispatch_once_t once
; 
 314         dispatch_once(&once
, ^{ 
 316                  * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock 
 317                  * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1) 
 318                  * which locks _asl_global.lock. 
 320                 _asl_global
.asl 
= (asl_client_t 
*)asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); 
 322                 /* Reset options to clear ASL_OPT_NO_REMOTE bit */ 
 323                 if (_asl_global
.asl 
!= NULL
) _asl_global
.asl
->options 
= 0; 
 325                 /* Now call _asl_notify_open(0) to finish the work */ 
 329         return _asl_global
.asl
; 
 333  * asl_add_file: write log messages to the given file descriptor 
 334  * Log messages will be written to this file as well as to the server. 
 337 asl_add_output_file(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
) 
 339         int status
, use_global_lock 
= 0; 
 342         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 344         asl 
= (asl_client_t 
*)client
; 
 347                 asl 
= _asl_open_default(); 
 348                 if (asl 
== NULL
) return -1; 
 349                 pthread_mutex_lock(&_asl_global
.lock
); 
 353         status 
= asl_client_add_output_file(asl
, fd
, mfmt
, tfmt
, filter
, text_encoding
); 
 355         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 356         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 359 /* returns previous filter value or -1 on error */ 
 361 asl_set_output_file_filter(asl_object_t client
, int fd
, int filter
) 
 364         int use_global_lock 
= 0; 
 367         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 369         asl 
= (asl_client_t 
*)client
; 
 372                 asl 
= _asl_open_default(); 
 373                 if (asl 
== NULL
) return -1; 
 374                 pthread_mutex_lock(&_asl_global
.lock
); 
 378         last 
= asl_client_set_output_file_filter(asl
, fd
, filter
); 
 380         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 384 /* SPI - Deprecated */ 
 386 asl_add_output(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
) 
 388         return asl_add_output_file(client
, fd
, mfmt
, tfmt
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), text_encoding
); 
 391 /* SPI - Deprecated */ 
 393 asl_add_log_file(asl_object_t client
, int fd
) 
 395         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
); 
 399  * asl_remove_output: stop writing log messages to the given file descriptor 
 402 asl_remove_output_file(asl_object_t client
, int fd
) 
 404         int status
, use_global_lock 
= 0; 
 407         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 409         asl 
= (asl_client_t 
*)client
; 
 412                 asl 
= _asl_open_default(); 
 413                 if (asl 
== NULL
) return -1; 
 414                 pthread_mutex_lock(&_asl_global
.lock
); 
 418         status 
= asl_client_remove_output_file(asl
, fd
); 
 420         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 421         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 425 asl_remove_output(asl_object_t client
, int fd
) 
 427         return asl_remove_output_file(client
, fd
); 
 431 asl_remove_log_file(asl_object_t client
, int fd
) 
 433         return asl_remove_output_file(client
, fd
); 
 436 /* returns previous filter value or -1 on error */ 
 438 asl_set_filter(asl_object_t client
, int f
) 
 440         int last
, use_global_lock 
= 0; 
 443         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 445         asl 
= (asl_client_t 
*)client
; 
 448                 asl 
= _asl_open_default(); 
 449                 if (asl 
== NULL
) return -1; 
 450                 pthread_mutex_lock(&_asl_global
.lock
); 
 454         last 
= asl_client_set_filter(asl
, f
); 
 456         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
 462 #pragma mark message sending 
 465  * Evaluate client / message / level to determine what to do with a message. 
 466  * Checks filters, tunneling, and log files. 
 467  * Returns the bits below, ORed with the message level. 
 469  * EVAL_SEND_ASL        - send this message to syslogd 
 470  * EVAL_SEND_TRACE      - log this message with Activity Tracing 
 471  * EVAL_ASL_FILE        - write to a standalone ASL file (see asl_open_from_file) 
 472  * EVAL_TEXT_FILE       - write this message to a text file / stderr 
 473  * EVAL_TUNNEL          - tunneling enabled when sending to syslogd 
 476 _asl_evaluate_send(asl_object_t client
, asl_object_t m
, int slevel
) 
 479         asl_msg_t 
*msg 
= (asl_msg_t 
*)m
; 
 480         uint32_t level
, lmask
, filter
, status
, tunnel
; 
 486         level 
= ASL_LEVEL_DEBUG
; 
 487         if (slevel 
>= 0) level 
= slevel
; 
 490         if ((asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
) == 0) && (val 
!= NULL
)) level 
= atoi(val
); 
 492         if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 493         else if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 495         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) 
 497                 /* sending to something other than a client */ 
 498                 return EVAL_ACTIVE 
| EVAL_SEND_ASL 
| level
; 
 501         asl 
= (asl_client_t 
*)client
; 
 502         if ((asl 
!= NULL
) && (asl
->aslfile 
!= NULL
)) return (EVAL_ASL_FILE 
| level
); 
 504         if (asl 
== NULL
) asl 
= _asl_open_default(); 
 507                 eval 
= EVAL_ACTIVE 
| EVAL_DEFAULT_ACTION 
| level
; 
 508                 eval 
&= ~EVAL_SEND_ASL
; 
 512         eval 
= (asl_client_get_control(asl
) & EVAL_ACTION_MASK
) | level
; 
 514         filter 
= asl
->filter 
& 0xff; 
 515         tunnel 
= (asl
->filter 
& ASL_FILTER_MASK_TUNNEL
) >> 8; 
 516         if (tunnel 
!= 0) eval 
|= EVAL_TUNNEL
; 
 518         if ((asl
->options 
& ASL_OPT_NO_REMOTE
) == 0) 
 520                 pthread_mutex_lock(&_asl_global
.lock
); 
 522                 if (_asl_global
.rc_change_token 
>= 0) 
 524                         /* initialize or re-check process-specific and master filters  */ 
 526                         status 
= notify_check(_asl_global
.rc_change_token
, &check
); 
 527                         if ((status 
== NOTIFY_STATUS_OK
) && (check 
!= 0)) 
 529                                 if (_asl_global
.master_token 
>= 0) 
 532                                         status 
= notify_get_state(_asl_global
.master_token
, &v64
); 
 533                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.master_filter 
= v64
; 
 536                                 if (_asl_global
.notify_token 
>= 0) 
 539                                         status 
= notify_get_state(_asl_global
.notify_token
, &v64
); 
 540                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter 
= v64
; 
 545                 if (_asl_global
.master_filter 
& EVAL_ACTIVE
) 
 547                         /* clear bits and set according to master */ 
 548                         eval 
&= ~(EVAL_SEND_ASL 
| EVAL_SEND_TRACE
); 
 549                         eval 
|= (_asl_global
.master_filter 
& (EVAL_SEND_ASL 
| EVAL_SEND_TRACE
)); 
 552                         if ((_asl_global
.master_filter 
& EVAL_LEVEL_MASK
) != 0) filter 
= _asl_global
.proc_filter 
& EVAL_LEVEL_MASK
; 
 555                 if (_asl_global
.proc_filter 
& EVAL_ACTIVE
) 
 557                         /* clear bits and set according to proc */ 
 558                         eval 
&= ~(EVAL_SEND_ASL 
| EVAL_SEND_TRACE 
| EVAL_TEXT_FILE
); 
 559                         eval 
|= (_asl_global
.proc_filter 
& (EVAL_SEND_ASL 
| EVAL_SEND_TRACE 
| EVAL_TEXT_FILE
)); 
 562                         if ((_asl_global
.proc_filter 
& EVAL_LEVEL_MASK
) != 0) filter 
= _asl_global
.proc_filter 
& EVAL_LEVEL_MASK
; 
 565                 pthread_mutex_unlock(&_asl_global
.lock
); 
 568         lmask 
= ASL_FILTER_MASK(level
); 
 569         if ((filter 
!= 0) && ((filter 
& lmask
) == 0)) eval 
&= ~EVAL_SEND_ASL
; 
 570         if (asl
->out_count 
> 0) eval 
|= EVAL_TEXT_FILE
; 
 572         /* don't send MessageTracer messages to Activity Tracing */ 
 574         if ((asl_msg_lookup(msg
, ASL_KEY_MESSAGETRACER
, &val
, NULL
) == 0) && (val 
!= NULL
)) 
 576                 eval 
&= ~EVAL_SEND_TRACE
; 
 577                 eval 
|= EVAL_MT_SHIM
; 
 580         /* don't send PowerManagement messages to Activity Tracing */ 
 582         if ((asl_msg_lookup(msg
, ASL_KEY_POWERMANAGEMENT
, &val
, NULL
) == 0) && (val 
!= NULL
)) eval 
&= ~EVAL_SEND_TRACE
; 
 584         /* don't send control messages to Activity Tracing */ 
 586         if ((asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
) == 0) && (val 
!= NULL
)) eval 
&= ~EVAL_SEND_TRACE
; 
 588         /* don't send CFLog messages to Activity Tracing */ 
 590         if ((asl_msg_lookup(msg
, ASL_KEY_CFLOG_LOCAL_TIME
, &val
, NULL
) == 0) && (val 
!= NULL
)) eval 
&= ~EVAL_SEND_TRACE
; 
 593         if (((asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &val
, NULL
) == 0) && (val 
!= NULL
)) || 
 594                 ((asl_msg_lookup(asl
->kvdict
, ASL_KEY_FACILITY
, &val
, NULL
) == 0) && (val 
!= NULL
))) 
 596                 /* don't send lastlog/utmp messages to Activity Tracing */ 
 597                 if (!strcmp(val
, FACILITY_LASTLOG
) || !strcmp(val
, FACILITY_UTMPX
)) eval 
&= ~EVAL_SEND_TRACE
; 
 599                 /* don't send LOG_INSTALL messages to Activity Tracing */ 
 600                 if (!strcmp(val
, asl_syslog_faciliy_num_to_name(LOG_INSTALL
))) eval 
&= ~EVAL_SEND_TRACE
; 
 608  * Internal routine used by asl_vlog. 
 609  * msg:  an asl messsage 
 610  * eval: log level and send flags for the message 
 611  * format: A formating string 
 612  * ap: va_list for the format 
 613  * returns 0 for success, non-zero for failure 
 616 __private_extern__ ASL_STATUS
 
 617 _asl_lib_vlog_text(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
) 
 619     int saved_errno 
= errno
; 
 621     char *str
, *fmt
, estr
[NL_TEXTMAX
]; 
 622     uint32_t i
, len
, elen
, expand
; 
 624     if (format 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 626     /* insert strerror for %m */ 
 631     for (i 
= 0; format
[i
] != '\0'; i
++) 
 633         if (format
[i
] == '%') 
 635             if (format
[i
+1] == '\0') len
++; 
 636             else if (format
[i
+1] == 'm') 
 639                 strerror_r(saved_errno
, estr
, sizeof(estr
)); 
 653     fmt 
= (char *)format
; 
 657         fmt 
= malloc(len 
+ 1); 
 658         if (fmt 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 662         for (i 
= 0; format
[i
] != '\0'; i
++) 
 664             if (format
[i
] == '%') 
 666                 if (format
[i
+1] == '\0') 
 669                 else if ((format
[i
+1] == 'm') && (elen 
!= 0)) 
 671                     memcpy(fmt
+len
, estr
, elen
); 
 677                     fmt
[len
++] = format
[i
++]; 
 678                     fmt
[len
++] = format
[i
]; 
 681             else fmt
[len
++] = format
[i
]; 
 688     vasprintf(&str
, fmt
, ap
); 
 689     if (expand 
!= 0) free(fmt
); 
 691     if (str 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 693     status 
= _asl_send_message_text(NULL
, NULL
, obj
, eval
, (asl_msg_t 
*)msg
, str
, true); 
 701  * Internal routine used by asl_vlog. 
 702  * msg:  an asl messsage 
 703  * eval: log level and send flags for the message 
 704  * format: A formating string 
 705  * ap: va_list for the format 
 706  * returns 0 for success, non-zero for failure 
 708 __private_extern__ ASL_STATUS
 
 709 _asl_lib_vlog(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
) 
 711         int saved_errno 
= errno
; 
 713         char *str
, *fmt
, estr
[NL_TEXTMAX
]; 
 714         uint32_t i
, len
, elen
, expand
; 
 716         if (format 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 718         /* insert strerror for %m */ 
 723         for (i 
= 0; format
[i
] != '\0'; i
++) 
 725                 if (format
[i
] == '%') 
 727                         if (format
[i
+1] == '\0') len
++; 
 728                         else if (format
[i
+1] == 'm') 
 731                                 strerror_r(saved_errno
, estr
, sizeof(estr
)); 
 745         fmt 
= (char *)format
; 
 749                 fmt 
= malloc(len 
+ 1); 
 750                 if (fmt 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 754                 for (i 
= 0; format
[i
] != '\0'; i
++) 
 756                         if (format
[i
] == '%') 
 758                                 if (format
[i
+1] == '\0') 
 761                                 else if ((format
[i
+1] == 'm') && (elen 
!= 0)) 
 763                                         memcpy(fmt
+len
, estr
, elen
); 
 769                                         fmt
[len
++] = format
[i
++]; 
 770                                         fmt
[len
++] = format
[i
]; 
 773                         else fmt
[len
++] = format
[i
]; 
 780         vasprintf(&str
, fmt
, ap
); 
 781         if (expand 
!= 0) free(fmt
); 
 783         if (str 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 785         status 
= _asl_send_message(obj
, eval
, (asl_msg_t 
*)msg
, str
); 
 793  * Similar to asl_log, but take a va_list instead of a list of arguments. 
 794  * msg:  an asl message 
 795  * level: the log level of the associated message 
 796  * format: A formating string 
 797  * ap: va_list for the format 
 798  * returns 0 for success, non-zero for failure 
 801 asl_vlog(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, va_list ap
) 
 803         ASL_STATUS status 
= ASL_STATUS_OK
; 
 804         uint32_t eval 
= _asl_evaluate_send(client
, msg
, level
); 
 805         void *addr 
= __builtin_return_address(0); 
 807         if ((eval 
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
)) 
 810                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 811                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 812                 os_log_type_t type 
= shim_asl_to_log_type
[level
]; 
 814                 va_copy(ap_copy
, ap
); 
 815                 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap_copy
, addr
); 
 818                 if (eval 
& EVAL_TEXT_FILE
) 
 820                         status 
= _asl_lib_vlog_text(client
, eval
, msg
, format
, ap
); 
 823         else if (eval 
& EVAL_ASL
) 
 825                 status 
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
); 
 828         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 833  * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and 
 834  * forwards the call to _asl_lib_vlog. 
 835  * msg:  an asl message 
 836  * eval: log level and send flags for the message 
 837  * format: A formating string 
 838  * ... args for format 
 839  * returns 0 for success, non-zero for failure 
 842 _asl_lib_log(asl_object_t client
, uint32_t eval
, asl_object_t msg
, const char *format
, ...) 
 850                 va_start(ap
, format
); 
 851                 status 
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
); 
 860  * Processes an ASL log message. 
 861  * msg:  an asl message 
 862  * level: the log level of the associated message 
 863  * format: A formating string 
 864  * ... args for format 
 865  * returns 0 for success, non-zero for failure 
 868 asl_log(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, ...) 
 870         ASL_STATUS status 
= ASL_STATUS_OK
; 
 871         uint32_t eval 
= _asl_evaluate_send(client
, msg
, level
); 
 872         void *addr 
= __builtin_return_address(0); 
 874         if ((eval 
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
)) 
 877                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 878                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 879                 os_log_type_t type 
= shim_asl_to_log_type
[level
]; 
 881                 va_start(ap
, format
); 
 882                 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
); 
 885                 if (eval 
& EVAL_TEXT_FILE
) 
 888                         va_start(ap
, format
); 
 889                         status 
= _asl_lib_vlog_text(client
, eval
, msg
, format
, ap
); 
 893         else if (eval 
& EVAL_ASL
) 
 896                 va_start(ap
, format
); 
 897                 status 
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
); 
 901         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 906  * Like asl_log, supplies NULL client and msg. 
 907  * level: the log level of the associated message 
 908  * format: A formating string 
 909  * ... args for format 
 910  * returns 0 for success, non-zero for failure 
 913 asl_log_message(int level
, const char *format
, ...) 
 915         ASL_STATUS status 
= ASL_STATUS_OK
; 
 916         uint32_t eval 
= _asl_evaluate_send(NULL
, NULL
, level
); 
 917         void *addr 
= __builtin_return_address(0); 
 919         if ((eval 
& EVAL_SEND_TRACE
) && os_log_shim_enabled(addr
)) 
 922                 if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
 923                 if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
 924                 os_log_type_t type 
= shim_asl_to_log_type
[level
]; 
 926                 va_start(ap
, format
); 
 927                 os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
); 
 930                 if (eval 
& EVAL_TEXT_FILE
) 
 933                         va_start(ap
, format
); 
 934                         status 
= _asl_lib_vlog_text(NULL
, eval
, NULL
, format
, ap
); 
 938         else if (eval 
& EVAL_ASL
) 
 941                 va_start(ap
, format
); 
 942                 status 
= _asl_lib_vlog(NULL
, eval
, NULL
, format
, ap
); 
 946         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
 950  * asl_get_filter: gets the values for the local, master, and remote filters,  
 951  * and indicates which one is active. 
 954 asl_get_filter(asl_object_t client
, int *local
, int *master
, int *remote
, int *active
) 
 956         asl_client_t 
*asl
, *asl_default
; 
 961         if ((client 
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1; 
 968         asl_default 
= _asl_open_default(); 
 970         asl 
= (asl_client_t 
*)client
; 
 971         if (asl 
== NULL
) asl 
= asl_default
; 
 972         if (asl 
!= NULL
) l 
= asl
->filter 
& EVAL_LEVEL_MASK
; 
 974         if ((asl_default 
!= NULL
) && (!(asl_default
->options 
& ASL_OPT_NO_REMOTE
))) 
 976                 pthread_mutex_lock(&_asl_global
.lock
); 
 978                 if (_asl_global
.rc_change_token 
>= 0) 
 980                         /* initialize or re-check process-specific and master filters  */ 
 982                         status 
= notify_check(_asl_global
.rc_change_token
, &check
); 
 983                         if ((status 
== NOTIFY_STATUS_OK
) && (check 
!= 0)) 
 985                                 if (_asl_global
.master_token 
>= 0) 
 988                                         status 
= notify_get_state(_asl_global
.master_token
, &v64
); 
 989                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.master_filter 
= v64
; 
 992                                 if (_asl_global
.notify_token 
>= 0) 
 995                                         status 
= notify_get_state(_asl_global
.notify_token
, &v64
); 
 996                                         if (status 
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter 
= v64
; 
1001                 m 
= _asl_global
.master_filter
; 
1004                 r 
= _asl_global
.proc_filter
; 
1007                 pthread_mutex_unlock(&_asl_global
.lock
); 
1010         if (local 
!= NULL
) *local 
= l
; 
1011         if (master 
!= NULL
) *master 
= m
; 
1012         if (remote 
!= NULL
) *remote 
= r
; 
1013         if (active 
!= NULL
) *active 
= x
; 
1018 /* SPI for SHIM control */ 
1020 asl_set_local_control(asl_object_t client
, uint32_t filter
) 
1022         asl_client_t 
*asl 
= (asl_client_t 
*)client
; 
1025                 asl 
= _asl_open_default(); 
1026                 if (asl 
== NULL
) return UINT32_MAX
; 
1028         else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
; 
1030         return asl_client_set_control(asl
, filter
); 
1034 asl_get_local_control(asl_object_t client
) 
1036         asl_client_t 
*asl 
= (asl_client_t 
*)client
; 
1039                 asl 
= _asl_open_default(); 
1040                 if (asl 
== NULL
) return UINT32_MAX
; 
1042         else if (asl_get_type(client
) != ASL_TYPE_CLIENT
) return UINT32_MAX
; 
1044         return asl_client_get_control(asl
); 
1048  * Sets PID and OSActivityID values in a new message. 
1049  * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided. 
1052 asl_base_msg(asl_client_t 
*asl
, uint32_t level
, const struct timeval 
*tv
, const char *sstr
, const char *fstr
, const char *mstr
) 
1057         os_activity_id_t osaid
; 
1059         aux 
= asl_msg_new(ASL_TYPE_MSG
); 
1060         if (aux 
== NULL
) return NULL
; 
1063         if (level 
<= 7) asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, level_to_number_string
[level
]); 
1065         /* Time and TimeNanoSec */ 
1068                 snprintf(aux_val
, sizeof(aux_val
), "%llu", (unsigned long long) tv
->tv_sec
); 
1069                 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
); 
1071                 snprintf(aux_val
, sizeof(aux_val
), "%d", tv
->tv_usec 
* 1000); 
1072                 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
); 
1076         if (mstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstr
); 
1079         snprintf(aux_val
, sizeof(aux_val
), "%u", getpid()); 
1080         asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
); 
1083         osaid 
= os_activity_get_identifier(OS_ACTIVITY_CURRENT
, NULL
); 
1086                 snprintf(aux_val
, sizeof(aux_val
), "0x%016llx", osaid
); 
1087                 asl_msg_set_key_val(aux
, ASL_KEY_OS_ACTIVITY_ID
, aux_val
); 
1091         if ((sstr 
== NULL
) && (asl 
!= NULL
)) 
1093                 /* See if the client has a value for ASL_KEY_SENDER */ 
1094                 status 
= asl_msg_lookup((asl_msg_t 
*)asl
->kvdict
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1095                 if ((status 
!= 0) || (sstr 
== NULL
)) 
1099                         /* See if the global cache has a value for ASL_KEY_SENDER */ 
1100                         if (_asl_global
.sender 
== NULL
) 
1102                                 /* Get the process name with _NSGetArgv */ 
1103                                 char *name 
= *(*_NSGetArgv()); 
1106                                         char *x 
= strrchr(name
, '/'); 
1110                                         /* Set the cache value */ 
1111                                         pthread_mutex_lock(&_asl_global
.lock
); 
1112                                         if (_asl_global
.sender 
== NULL
) _asl_global
.sender 
= strdup(x
); 
1113                                         pthread_mutex_unlock(&_asl_global
.lock
); 
1117                         if (_asl_global
.sender 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
); 
1118                         else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown"); 
1122         if (sstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, sstr
); 
1125         if ((fstr 
== NULL
) && (asl 
!= NULL
)) 
1127                 status 
= asl_msg_lookup((asl_msg_t 
*)asl
->kvdict
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1128                 if (status 
!= 0) fstr 
= NULL
; 
1131         if (fstr 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, fstr
); 
1138  * Possibly useful someday... 
1141 asl_prepared_message(asl_client_t 
*asl
, asl_msg_t 
*msg
) 
1143         uint32_t i
, len
, level
, outstatus
; 
1144         const char *val
, *sstr
, *fstr
; 
1145         struct timeval tval 
= {0, 0}; 
1151                 asl 
= _asl_open_default(); 
1152                 if (asl 
== NULL
) return NULL
; 
1155         status 
= gettimeofday(&tval
, NULL
); 
1158                 time_t tick 
= time(NULL
); 
1164         status 
= asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
); 
1165         if (status 
!= 0) val 
= NULL
; 
1167         level 
= ASL_LEVEL_DEBUG
; 
1168         if (val 
!= NULL
) level 
= atoi(val
); 
1169         if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
1172         status 
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1173         if (status 
!= 0) sstr 
= NULL
; 
1176         status 
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1177         if (status 
!= 0) fstr 
= NULL
; 
1179         out 
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, NULL
); 
1180         out 
= asl_msg_merge(out
, msg
); 
1187 _asl_set_option(asl_msg_t 
*msg
, const char *opt
) 
1189         const char *val 
= NULL
; 
1192         if (msg 
== NULL
) return; 
1193         if (opt 
== NULL
) return; 
1195         status 
= asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
); 
1196         if ((status 
!= 0) || (val 
== NULL
)) 
1198                 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, opt
); 
1202                 char *option 
= NULL
; 
1203                 asprintf(&option
, "%s %s", opt
, val
); 
1204                 asl_msg_set_key_val(msg
, ASL_KEY_OPTION
, option
); 
1210 _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
) 
1213     uint32_t level
, lmask
; 
1214     asl_msg_t 
*release_sendmsg 
= NULL
; 
1218             asl 
= _asl_open_default(); 
1219             if (asl 
== NULL
) return ASL_STATUS_FAILED
; 
1221             uint32_t objtype 
= asl_get_type(obj
); 
1222             if (objtype 
== ASL_TYPE_CLIENT
) asl 
= (asl_client_t 
*)obj
; 
1226     level 
= eval 
& EVAL_LEVEL_MASK
; 
1227     if (level 
> 7) level 
= 7; 
1228     lmask 
= ASL_FILTER_MASK(level
); 
1230     if (sendmsg 
== NULL
) { 
1231         struct timeval tval 
= {0, 0}; 
1232         const char *sstr
, *fstr
; 
1234         status 
= gettimeofday(&tval
, NULL
); 
1236             time_t tick 
= time(NULL
); 
1242         status 
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1248         status 
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1252         sendmsg 
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
); 
1253         if (sendmsg 
== NULL
) { 
1254             return ASL_STATUS_FAILED
; 
1257         release_sendmsg 
= sendmsg 
= asl_msg_merge(sendmsg
, msg
); 
1260     /* write to file descriptors */ 
1261     for (uint32_t i 
= 0; i 
< asl
->out_count
; i
++) { 
1263             if ((asl
->out_list
[i
].fd 
!= STDOUT_FILENO
) && (asl
->out_list
[i
].fd 
!= STDERR_FILENO
)) { 
1264                 continue; // new logging only support stdout/stderr 
1268         if ((asl
->out_list
[i
].fd 
>= 0) && (asl
->out_list
[i
].filter 
!= 0) && ((asl
->out_list
[i
].filter 
& lmask
) != 0)) { 
1272             str 
= asl_format_message(sendmsg
, asl
->out_list
[i
].mfmt
, asl
->out_list
[i
].tfmt
, asl
->out_list
[i
].encoding
, &len
); 
1273             if (str 
== NULL
) continue; 
1275             status 
= write(asl
->out_list
[i
].fd
, str
, len 
- 1); 
1278                 /* soft error for fd 2 (stderr) */ 
1279                 if (asl
->out_list
[i
].fd 
== 2) status 
= 0; 
1280                 asl
->out_list
[i
].fd 
= -1; 
1288     if (release_sendmsg
) { 
1289         asl_msg_release(release_sendmsg
); 
1296 _asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t 
*msg
, const char *mstr
) 
1298         uint32_t len
, level
, lmask
, outstatus
, objtype
; 
1299         const char *sstr
, *fstr
; 
1300         struct timeval tval 
= {0, 0}; 
1302         int use_global_lock 
= 0; 
1303         kern_return_t kstatus
; 
1305         asl_msg_t 
*qd_msg 
= NULL
; 
1306         asl_client_t 
*asl 
= NULL
; 
1307         static dispatch_once_t noquota_once
; 
1308         __block 
int log_quota_msg 
= 0; 
1310         if ((eval 
& EVAL_ASL
) == 0) return ASL_STATUS_OK
; 
1314                 asl 
= _asl_open_default(); 
1315                 if (asl 
== NULL
) return ASL_STATUS_FAILED
; 
1316                 use_global_lock 
= 1; 
1317                 objtype 
= ASL_TYPE_CLIENT
; 
1321                 objtype 
= asl_get_type(obj
); 
1322                 if (objtype 
== ASL_TYPE_CLIENT
) asl 
= (asl_client_t 
*)obj
; 
1325         level 
= eval 
& EVAL_LEVEL_MASK
; 
1326         if (level 
> 7) level 
= 7; 
1327         lmask 
= ASL_FILTER_MASK(level
); 
1329         if ((objtype 
== ASL_TYPE_CLIENT
) && (asl
->aslfile 
!= NULL
)) use_global_lock 
= 1; 
1331         status 
= gettimeofday(&tval
, NULL
); 
1334                 time_t tick 
= time(NULL
); 
1340         status 
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
); 
1341         if (status 
!= 0) sstr 
= NULL
; 
1344         status 
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
); 
1345         if (status 
!= 0) fstr 
= NULL
; 
1347         sendmsg 
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
); 
1348         if (sendmsg 
== NULL
) return ASL_STATUS_FAILED
; 
1350         /* Set "ASLOption store" if tunneling */ 
1351         if (eval 
& EVAL_TUNNEL
) _asl_set_option(sendmsg
, ASL_OPT_STORE
); 
1355         if (use_global_lock 
!= 0) pthread_mutex_lock(&_asl_global
.lock
); 
1357         sendmsg 
= asl_msg_merge(sendmsg
, msg
); 
1359         if (objtype 
!= ASL_TYPE_CLIENT
) 
1361                 asl_append(obj
, (asl_object_t
)sendmsg
); 
1362                 asl_msg_release(sendmsg
); 
1363                 if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1364                 return ASL_STATUS_OK
; 
1368          * If there is an aslfile this is a stand-alone file client. 
1369          * Just save to the file. 
1371         if (asl
->aslfile 
!= NULL
) 
1373                 outstatus 
= ASL_STATUS_FAILED
; 
1375                 if (sendmsg 
!= NULL
) 
1377                         outstatus 
= asl_file_save(asl
->aslfile
, sendmsg
, &(asl
->aslfileid
)); 
1381                 asl_msg_release(sendmsg
); 
1383                 if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1391          * Quotas are disabled if: 
1392          * - a remote control filter is in place (EVAL_TUNNEL) 
1393          * - Environment variable ASL_QUOTA_DISABLED == 1 
1394          * - /etc/asl/.noquota existed at the time that the process started 
1396          * We just check /etc/asl/.noquota once, since it would be 
1397          * expensive to stat() for every log message. 
1399          * We only check the Environment variable once, since getenv() is 
1400          * not thread safe.  If someone is changing the environment, 
1404         dispatch_once(&noquota_once
, ^{ 
1406                 memset(&sb
, 0, sizeof(struct stat
)); 
1408                 int save_errno 
= errno
; 
1410                 if (stat(NOQUOTA_FILE_PATH
, &sb
) == 0) 
1412                         _asl_global
.quota 
= UINT32_MAX
; 
1416                         const char *qtest 
= getenv(NOQUOTA_ENV
); 
1417                         if ((qtest 
!= NULL
) && (!strcmp(qtest
, "1"))) 
1419                                 _asl_global
.quota 
= UINT32_MAX
; 
1424                 /* reset errno since we want stat() to fail silently */ 
1428         if (log_quota_msg 
!= 0) 
1430                 qd_msg 
= asl_base_msg(asl
, QUOTA_LEVEL
, &tval
, sstr
, fstr
, QUOTA_DISABLED_MSG
); 
1431                 asl_msg_set_key_val(qd_msg
, ASL_KEY_OPTION
, ASL_OPT_STORE
); 
1434         if (((eval 
& EVAL_TUNNEL
) == 0) && (_asl_global
.quota 
!= UINT32_MAX
)) 
1436                 time_t last_send 
= _asl_global
.last_send
; 
1437                 time_t last_oq 
= _asl_global
.last_oq_msg
; 
1438                 uint32_t qcurr 
= _asl_global
.quota
; 
1440                 uint32_t qinc
, qnew
; 
1444                 /* add QUOTA_MPS to quota for each second we've been idle */ 
1445                 if (tval
.tv_sec 
> last_send
) 
1447                         delta 
= tval
.tv_sec 
- last_send
; 
1450                         if (delta 
< (QUOTA_MPH 
/ QUOTA_MPS
)) qinc 
= delta 
* QUOTA_MPS
; 
1452                         qnew 
= MIN(QUOTA_MPH
, qcurr 
+ qinc
); 
1453                         OSAtomicCompareAndSwapLongBarrier(last_send
, tval
.tv_sec
, (long *)&_asl_global
.last_send
); 
1458                         if ((tval
.tv_sec 
- last_oq
) > QUOTA_MSG_INTERVAL
) 
1461                                 OSAtomicCompareAndSwapLongBarrier(last_oq
, tval
.tv_sec
, (long *)&_asl_global
.last_oq_msg
); 
1465                                 eval 
&= ~EVAL_SEND_ASL
; 
1470                         OSAtomicCompareAndSwap32Barrier(qcurr
, qnew 
- 1, (int32_t *)&_asl_global
.quota
); 
1475         if (eval 
& EVAL_MT_SHIM
) 
1477                 _asl_mt_shim_send_message(sendmsg
); 
1482         if ((_asl_global
.server_port 
!= MACH_PORT_NULL
) && (eval 
& EVAL_SEND_ASL
)) 
1484                 asl_string_t 
*send_str
; 
1488                 if (eval 
& EVAL_QUOTA
) 
1490                         asl_msg_set_key_val(sendmsg
, ASL_KEY_LEVEL
, QUOTA_LEVEL_STR
); 
1491                         asl_msg_set_key_val(sendmsg
, ASL_KEY_MSG
, QUOTA_MSG
); 
1496                         send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, qd_msg
, "raw"); 
1497                         len 
= asl_string_length(send_str
); 
1498                         vmsize 
= asl_string_allocated_size(send_str
); 
1499                         str 
= asl_string_release_return_bytes(send_str
); 
1502                                 kstatus 
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
); 
1503                                 if (kstatus 
!= KERN_SUCCESS
) 
1505                                         vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1508                         else if (vmsize 
!= 0) 
1510                                 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1512                         asl_msg_release(qd_msg
); 
1515                 send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, sendmsg
, "raw"); 
1516                 len 
= asl_string_length(send_str
); 
1518                 if (len 
> LIBASL_MAX_MSG_SIZE
) 
1522                         snprintf(tmp
, sizeof(tmp
), SIZE_LIMIT_MSG
, len
, LIBASL_MAX_MSG_SIZE
); 
1523                         asl_msg_t 
*limitmsg 
= asl_base_msg(asl
, ASL_LEVEL_CRIT
, &tval
, sstr
, fstr
, tmp
); 
1525                         asl_string_release(send_str
); 
1528                         if (limitmsg 
!= NULL
) 
1530                                 /* Set "ASLOption store" if tunneling */ 
1531                                 if (eval 
& EVAL_TUNNEL
) _asl_set_option(limitmsg
, ASL_OPT_STORE
); 
1533                                 send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, limitmsg
, "raw"); 
1534                                 len 
= asl_string_length(send_str
); 
1535                                 asl_msg_release(limitmsg
); 
1539                 vmsize 
= asl_string_allocated_size(send_str
); 
1540                 str 
= asl_string_release_return_bytes(send_str
); 
1544                         /* send a mach message to syslogd */ 
1545                         kstatus 
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
); 
1546                         if (kstatus 
!= KERN_SUCCESS
) 
1548                                 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1552                 else if (vmsize 
>0) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1555         if ((sendmsg 
!= NULL
) && (asl
->out_count 
> 0)) 
1557                 status 
= _asl_send_message_text(asl
, sendmsg
, obj
, eval
, msg
, mstr
, false); 
1560         asl_msg_release(sendmsg
); 
1562         if (use_global_lock 
!= 0) pthread_mutex_unlock(&_asl_global
.lock
); 
1568 os_log_with_args_wrapper(void *addr
, int level
, const char *format
, ...) 
1571         if (level 
< ASL_LEVEL_EMERG
) level 
= ASL_LEVEL_EMERG
; 
1572         if (level 
> ASL_LEVEL_DEBUG
) level 
= ASL_LEVEL_DEBUG
; 
1573         os_log_type_t type 
= shim_asl_to_log_type
[level
]; 
1575         va_start(ap
, format
); 
1576         os_log_with_args(OS_LOG_DEFAULT
, type
, format
, ap
, addr
); 
1581  * asl_send: send a message  
1582  * This routine may be used instead of asl_log() or asl_vlog() if asl_set() 
1583  * has been used to set all of a message's attributes. 
1584  * eval:  hints about what to do with the message 
1585  * msg:  an asl message 
1586  * returns 0 for success, non-zero for failure 
1588 __private_extern__ ASL_STATUS
 
1589 asl_client_internal_send(asl_object_t obj
, asl_object_t msg
, void *addr
) 
1591         int status 
= ASL_STATUS_OK
; 
1592         uint32_t eval 
= _asl_evaluate_send(obj
, msg
, -1); 
1594         const char *message 
= asl_msg_get_val_for_key((asl_msg_t 
*)msg
, ASL_KEY_MSG
); 
1596         if ((eval 
& EVAL_SEND_TRACE
) && message 
&& message
[0] && os_log_shim_enabled(addr
)) 
1598                 int level 
= ASL_LEVEL_DEBUG
; 
1599                 const char *lval 
= asl_msg_get_val_for_key((asl_msg_t 
*)msg
, ASL_KEY_LEVEL
); 
1600                 if (lval 
!= NULL
) level 
= atoi(lval
); 
1603                  * If the return address and the format string are from different 
1604                  * binaries, os_log_with_args will not record the return address. 
1605                  * Work around this by passing a dynamic format string. 
1607                 char dynamic_format
[] = "%s"; 
1608                 os_log_with_args_wrapper(addr
, level
, dynamic_format
, message
); 
1610                 if (eval 
& EVAL_TEXT_FILE
) 
1612                         status 
= _asl_send_message_text(NULL
, NULL
, obj
, eval
, (asl_msg_t 
*)msg
, NULL
, true); 
1615         else if (eval 
& EVAL_ASL
) 
1617                 status 
= _asl_send_message(obj
, eval
, (asl_msg_t 
*)msg
, NULL
); 
1624 #pragma mark auxiliary files and URLs 
1627 _asl_aux_save_context(asl_aux_context_t 
*ctx
) 
1629         if (ctx 
== NULL
) return ASL_STATUS_FAILED
; 
1631         pthread_mutex_lock(&_asl_global
.lock
); 
1633         _asl_global
.aux_ctx 
= (asl_aux_context_t 
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count 
+ 1) * sizeof(asl_aux_context_t 
*)); 
1634         if (_asl_global
.aux_ctx 
== NULL
) 
1636                 _asl_global
.aux_count 
= 0; 
1637                 pthread_mutex_unlock(&_asl_global
.lock
); 
1638                 return ASL_STATUS_FAILED
; 
1641         _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
; 
1643         pthread_mutex_unlock(&_asl_global
.lock
); 
1645         return ASL_STATUS_OK
; 
1649  * Creates an auxiliary file that may be used to save arbitrary data.  The ASL message msg 
1650  * will be saved at the time that the auxiliary file is created.  The message will include 
1651  * any keys and values found in msg, and it will include the title and Uniform Type 
1652  * Identifier specified.  Output parameter out_fd will contain the file descriptor of the 
1653  * new auxiliary file. 
1656 _asl_auxiliary(asl_msg_t 
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
) 
1659         asl_string_t 
*send_str
; 
1661         fileport_t fileport
; 
1662         kern_return_t kstatus
; 
1664         uint32_t newurllen
, where
; 
1665         int status
, fd
, fdpair
[2]; 
1667         dispatch_queue_t pipe_q
; 
1668         dispatch_io_t pipe_channel
; 
1669         dispatch_semaphore_t sem
; 
1671         aux 
= asl_msg_new(ASL_TYPE_MSG
); 
1673         if (url 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
); 
1674         if (title 
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
); 
1675         if (uti 
== NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data"); 
1676         else asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
); 
1678         aux 
= asl_msg_merge(aux
, msg
); 
1680         /* if (out_fd == NULL), this is from asl_log_auxiliary_location */ 
1683                 uint32_t eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1); 
1684                 status 
= _asl_send_message(NULL
, eval
, aux
, NULL
); 
1685                 asl_msg_release(aux
); 
1689         where 
= asl_store_location(); 
1690         if (where 
== ASL_STORE_LOCATION_MEMORY
) 
1693                 asl_aux_context_t 
*ctx 
= (asl_aux_context_t 
*)calloc(1, sizeof(asl_aux_context_t
)); 
1694                 if (ctx 
== NULL
) return ASL_STATUS_FAILED
; 
1696                 status 
= pipe(fdpair
); 
1700                         return ASL_STATUS_FAILED
; 
1703                 /* give read end to dispatch_io_read */ 
1705                 sem 
= dispatch_semaphore_create(0); 
1707                 ctx
->fd 
= fdpair
[1]; 
1709                 status 
= _asl_aux_save_context(ctx
); 
1710                 if (status 
!= ASL_STATUS_OK
) 
1714                         dispatch_release(sem
); 
1716                         return ASL_STATUS_FAILED
; 
1719                 pipe_q 
= dispatch_queue_create("ASL_AUX_PIPE_Q", NULL
); 
1720                 pipe_channel 
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){ 
1724                 *out_fd 
= fdpair
[1]; 
1726                 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
); 
1728                 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){ 
1731                                 size_t len 
= dispatch_data_get_size(pipedata
); 
1734                                         const char *bytes 
= NULL
; 
1738                                         dispatch_data_t md 
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
); 
1739                                         encoded 
= asl_core_encode_buffer(bytes
, len
); 
1740                                         asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
); 
1742                                         eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1); 
1743                                         _asl_send_message(NULL
, eval
, aux
, NULL
); 
1744                                         asl_msg_release(aux
); 
1745                                         dispatch_release(md
); 
1751                                 dispatch_semaphore_signal(sem
); 
1752                                 dispatch_release(pipe_channel
); 
1753                                 dispatch_release(pipe_q
); 
1757                 return ASL_STATUS_OK
; 
1761         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return ASL_STATUS_FAILED
; 
1763         send_str 
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw"); 
1764         len 
= asl_string_length(send_str
); 
1765         vmsize 
= asl_string_allocated_size(send_str
); 
1766         str 
= asl_string_release_return_bytes(send_str
); 
1770                 asl_msg_release(aux
); 
1771                 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1772                 return ASL_STATUS_FAILED
; 
1776         fileport 
= MACH_PORT_NULL
; 
1777         status 
= KERN_SUCCESS
; 
1779         kstatus 
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
); 
1780         if (kstatus 
!= KERN_SUCCESS
) 
1782                 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
); 
1783                 asl_msg_release(aux
); 
1784                 return ASL_STATUS_FAILED
; 
1789                 asl_msg_release(aux
); 
1795                 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
); 
1796                 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
); 
1799         if (fileport 
== MACH_PORT_NULL
) 
1801                 asl_msg_release(aux
); 
1802                 return ASL_STATUS_FAILED
; 
1805         fd 
= fileport_makefd(fileport
); 
1806         mach_port_deallocate(mach_task_self(), fileport
); 
1809                 asl_msg_release(aux
); 
1814                 asl_aux_context_t 
*ctx 
= (asl_aux_context_t 
*)calloc(1, sizeof(asl_aux_context_t
)); 
1826                         status 
= _asl_aux_save_context(ctx
); 
1834 asl_create_auxiliary_file(asl_object_t msg
, const char *title
, const char *uti
, int *out_fd
) 
1836         if (out_fd 
== NULL
) return -1; 
1838         ASL_STATUS status 
= _asl_auxiliary((asl_msg_t 
*)msg
, title
, uti
, NULL
, out_fd
); 
1839         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
1843 asl_log_auxiliary_location(asl_object_t msg
, const char *title
, const char *uti
, const char *url
) 
1845         ASL_STATUS status 
= _asl_auxiliary((asl_msg_t 
*)msg
, title
, uti
, url
, NULL
); 
1846         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
1850  * Close an auxiliary file. 
1851  * Sends the cached auxiliary message to syslogd. 
1852  * Returns 0 on success, -1 on error. 
1855 asl_close_auxiliary_file(int fd
) 
1859         dispatch_semaphore_t aux_sem 
= NULL
; 
1861         pthread_mutex_lock(&(_asl_global
.lock
)); 
1866         for (i 
= 0; i 
< _asl_global
.aux_count
; i
++) 
1868                 if (_asl_global
.aux_ctx
[i
]->fd 
== fd
) 
1872                         aux_msg 
= _asl_global
.aux_ctx
[i
]->msg
; 
1873                         aux_sem 
= _asl_global
.aux_ctx
[i
]->sem
; 
1875                         free(_asl_global
.aux_ctx
[i
]); 
1877                         for (j 
= i 
+ 1; j 
< _asl_global
.aux_count
; i
++, j
++) 
1879                                 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
]; 
1882                         _asl_global
.aux_count
--; 
1884                         if (_asl_global
.aux_count 
== 0) 
1886                                 free(_asl_global
.aux_ctx
); 
1887                                 _asl_global
.aux_ctx 
= NULL
; 
1891                                 _asl_global
.aux_ctx 
= (asl_aux_context_t 
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count 
* sizeof(asl_aux_context_t 
*)); 
1892                                 if (_asl_global
.aux_ctx 
== NULL
) 
1894                                         _asl_global
.aux_count 
= 0; 
1903         pthread_mutex_unlock(&(_asl_global
.lock
)); 
1907         if (aux_msg 
!= NULL
) 
1909                 uint32_t eval 
= _asl_evaluate_send(NULL
, (asl_object_t
)aux_msg
, -1); 
1910                 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status 
= -1; 
1911                 asl_msg_release(aux_msg
); 
1914         if (aux_sem 
!= NULL
) 
1916                 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
); 
1917                 dispatch_release(aux_sem
); 
1926 _asl_server_control_query(void) 
1928         asl_msg_list_t 
*list 
= NULL
; 
1930         uint32_t len
, reslen
, status
; 
1931         uint64_t cmax
, qmin
; 
1932         kern_return_t kstatus
; 
1934         asl_msg_t 
*m 
= NULL
; 
1935         static const char ctlstr
[] = "1\nQ [= ASLOption control]\n"; 
1938         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return NULL
; 
1940         len 
= strlen(ctlstr
) + 1; 
1947         kstatus 
= vm_allocate(mach_task_self(), (vm_address_t 
*)&vmstr
, len
, VM_FLAGS_ANYWHERE 
| VM_MAKE_TAG(VM_MEMORY_ASL
)); 
1948         if (kstatus 
!= KERN_SUCCESS
) return NULL
; 
1950         memmove(vmstr
, ctlstr
, len
); 
1953         kstatus 
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1954         if (kstatus 
!= KERN_SUCCESS
) return NULL
; 
1956         list 
= asl_msg_list_from_string(res
); 
1957         vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
); 
1959         if (list 
== NULL
) return NULL
; 
1960         if (list
->count 
> 0) m 
= asl_msg_retain(list
->msg
[0]); 
1961         asl_msg_list_release(list
); 
1966  * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY 
1969 asl_store_location() 
1971         kern_return_t kstatus
; 
1973         uint32_t reslen
, status
; 
1977         if (_asl_global
.server_port 
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
; 
1982         status 
= ASL_STATUS_OK
; 
1984         kstatus 
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t 
*)&res
, &reslen
, &cmax
, (int *)&status
); 
1985         if (kstatus 
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
; 
1987         /* res should never be returned, but just to be certain we don't leak VM ... */ 
1988         if (res 
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
); 
1990         if (status 
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
; 
1991         return ASL_STORE_LOCATION_FILE
; 
1995 asl_open_path(const char *path
, uint32_t opts
) 
1998         asl_file_t 
*fout 
= NULL
; 
1999         asl_store_t 
*sout 
= NULL
; 
2001         if (opts 
== 0) opts 
= ASL_OPT_OPEN_READ
; 
2003         if (opts 
& ASL_OPT_OPEN_READ
) 
2007                         if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT
, &sout
) != ASL_STATUS_OK
) return NULL
; 
2008                         return (asl_object_t
)sout
; 
2011                 memset(&sb
, 0, sizeof(struct stat
)); 
2012                 if (stat(path
, &sb
) < 0) return NULL
; 
2014                 if (sb
.st_mode 
& S_IFREG
) 
2016                         if (asl_file_open_read(path
, &fout
) != ASL_STATUS_OK
) return NULL
; 
2017                         return (asl_object_t
)fout
; 
2019                 else if (sb
.st_mode 
& S_IFDIR
) 
2021                         if (asl_store_open_read(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
2022                         return (asl_object_t
)sout
; 
2027         else if (opts 
& ASL_OPT_OPEN_WRITE
) 
2029                 if (path 
== NULL
) return NULL
; 
2031                 memset(&sb
, 0, sizeof(struct stat
)); 
2032                 if (stat(path
, &sb
) < 0) 
2034                         if (errno 
!= ENOENT
) return NULL
; 
2036                         if (opts 
& ASL_OPT_CREATE_STORE
) 
2038                                 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
2039                                 return (asl_object_t
)sout
; 
2043                                 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
; 
2044                                 return (asl_object_t
)fout
; 
2047                 else if (sb
.st_mode 
& S_IFREG
) 
2049                         if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
; 
2050                         return (asl_object_t
)fout
; 
2052                 else if (sb
.st_mode 
& S_IFDIR
) 
2054                         if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
; 
2055                         return (asl_object_t
)sout
;