2 * Copyright (c) 2004-2012 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 <crt_externs.h>
42 #include <mach/mach.h>
43 #include <mach/std_types.h>
45 #include <mach/mach_types.h>
46 #include <sys/types.h>
47 #include <servers/bootstrap.h>
48 #include <bootstrap_priv.h>
50 #include <dispatch/dispatch.h>
51 #include <libkern/OSAtomic.h>
55 #include "asl_store.h"
56 #include "asl_private.h"
58 #define streq(A, B) (strcmp(A, B) == 0)
59 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
61 #define forever for(;;)
63 #define FETCH_BATCH 256
65 #define LEVEL_MASK 0x0000000f
66 #define EVAL_MASK 0x000000f0
67 #define EVAL_IGNORE 0x00000000
68 #define EVAL_ASLFILE 0x00000010
69 #define EVAL_SEND 0x00000020
70 #define EVAL_TUNNEL 0x00000040
71 #define EVAL_FILE 0x00000080
72 #define EVAL_QUOTA 0x00000100
75 * Clients get a max of 36000 messages per hour.
76 * Their quota gets refilled at a rate of 10 messages per second.
78 #define QUOTA_MPH 36000
80 #define QUOTA_MSG_INTERVAL 60
82 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
83 #define QUOTA_LEVEL "2"
86 time_t asl_parse_time(const char *);
87 const char *asl_syslog_faciliy_num_to_name(int n
);
88 static int _asl_send_message(aslclient ac
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
);
89 __private_extern__ asl_client_t
*_asl_open_default();
91 /* private asl_file SPI */
92 __private_extern__
uint32_t asl_file_open_write_fd(int fd
, asl_file_t
**s
);
95 uint32_t notify_register_plain(const char *name
, int *out_token
);
97 /* fork handling in syslog.c */
98 extern void _syslog_fork_child();
104 dispatch_semaphore_t sem
;
113 uint64_t proc_filter
;
114 uint64_t master_filter
;
118 dispatch_once_t port_lookup_once
;
119 mach_port_t server_port
;
121 pthread_mutex_t lock
;
123 asl_aux_context_t
**aux_ctx
;
128 #ifndef BUILDING_VARIANT
129 __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
};
131 #define ASL_SERVICE_NAME "com.apple.system.logger"
134 * Called from the child process inside fork() to clean up
135 * inherited state from the parent process.
137 * NB. A lock isn't required, since we're single threaded in this call.
142 _asl_global
.notify_count
= 0;
143 _asl_global
.rc_change_token
= -1;
144 _asl_global
.master_token
= -1;
145 _asl_global
.notify_token
= -1;
146 _asl_global
.quota
= 0;
147 _asl_global
.last_send
= 0;
148 _asl_global
.last_oq_msg
= 0;
150 _asl_global
.port_lookup_once
= 0;
151 _asl_global
.server_port
= MACH_PORT_NULL
;
153 pthread_mutex_init(&(_asl_global
.lock
), NULL
);
157 * asl_remote_notify_name: returns the notification key for remote-control filter
158 * changes for this process.
161 asl_remote_notify_name()
163 pid_t pid
= getpid();
164 uid_t euid
= geteuid();
167 if (euid
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
);
168 else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
);
174 _asl_notify_open(int do_lock
)
179 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
181 _asl_global
.notify_count
++;
183 if (_asl_global
.notify_token
!= -1)
185 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
189 if (_asl_global
.rc_change_token
== -1)
191 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
192 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
195 if (_asl_global
.master_token
== -1)
197 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
198 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
201 notify_name
= asl_remote_notify_name();
202 if (notify_name
!= NULL
)
204 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
206 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
209 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
211 if (_asl_global
.notify_token
== -1) return -1;
218 pthread_mutex_lock(&_asl_global
.lock
);
220 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
222 if (_asl_global
.notify_count
> 0)
224 pthread_mutex_unlock(&_asl_global
.lock
);
228 if (_asl_global
.rc_change_token
>= 0) notify_cancel(_asl_global
.rc_change_token
);
229 _asl_global
.rc_change_token
= -1;
231 if (_asl_global
.master_token
>= 0) notify_cancel(_asl_global
.master_token
);
232 _asl_global
.master_token
= -1;
234 if (_asl_global
.notify_token
>= 0) notify_cancel(_asl_global
.notify_token
);
235 _asl_global
.notify_token
= -1;
237 pthread_mutex_unlock(&_asl_global
.lock
);
243 if (_asl_global
.server_port
== MACH_PORT_NULL
)
245 mach_port_t newport
= MACH_PORT_NULL
;
246 char *str
= getenv("ASL_DISABLE");
247 if ((str
== NULL
) || strcmp(str
, "1"))
249 bootstrap_look_up2(bootstrap_port
, ASL_SERVICE_NAME
, &newport
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
250 if (newport
!= MACH_PORT_NULL
)
252 if (!OSAtomicCompareAndSwap32Barrier(MACH_PORT_NULL
, newport
, (int32_t *)&_asl_global
.server_port
))
254 mach_port_deallocate(mach_task_self(), newport
);
264 mach_port_t tmp
= _asl_global
.server_port
;
265 _asl_global
.server_port
= MACH_PORT_NULL
;
266 mach_port_deallocate(mach_task_self(), tmp
);
270 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
275 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
292 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
296 asl
->name
= strdup(ident
);
297 if (asl
->name
== NULL
)
299 if (asl
->sock
>= 0) close(asl
->sock
);
306 name
= *(*_NSGetArgv());
309 x
= strrchr(name
, '/');
312 asl
->name
= strdup(x
);
313 if (asl
->name
== NULL
)
315 if (asl
->sock
>= 0) close(asl
->sock
);
322 asl
->facility
= NULL
;
323 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
324 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
325 if (asl
->facility
== NULL
)
327 if (asl
->sock
>= 0) close(asl
->sock
);
328 if (asl
->name
!= NULL
) free(asl
->name
);
333 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
335 if (asl
->options
& ASL_OPT_STDERR
)
337 /* only add stderr if it is valid */
338 if (fcntl(STDERR_FILENO
, F_GETFD
) >= 0)
340 asl_add_output_file((aslclient
)asl
, STDERR_FILENO
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), ASL_ENCODE_SAFE
);
344 /* stderr has been closed, ignore ASL_OPT_STDERR flag */
345 asl
->options
&= ~ASL_OPT_STDERR
;
351 return (aslclient
)asl
;
355 asl_open_from_file(int fd
, const char *ident
, const char *facility
)
361 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
368 asl
->options
= ASL_OPT_NO_REMOTE
;
375 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
);
379 asl
->name
= strdup(ident
);
380 if (asl
->name
== NULL
)
388 name
= *(*_NSGetArgv());
391 x
= strrchr(name
, '/');
394 asl
->name
= strdup(x
);
395 if (asl
->name
== NULL
)
403 asl
->facility
= NULL
;
404 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
405 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
406 if (asl
->facility
== NULL
)
408 if (asl
->name
!= NULL
) free(asl
->name
);
413 status
= asl_file_open_write_fd(fd
, &(asl
->aslfile
));
414 if (status
!= ASL_STATUS_OK
)
416 if (asl
->name
!= NULL
) free(asl
->name
);
417 if (asl
->facility
!= NULL
) free(asl
->facility
);
425 return (aslclient
)asl
;
428 __private_extern__
void
429 asl_client_release(asl_client_t
*asl
)
433 if (asl
== NULL
) return;
435 if (OSAtomicDecrement32(&asl
->refcount
) > 0) return;
440 if (asl
->sock
>= 0) close(asl
->sock
);
441 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_close();
443 for (i
= 0; i
< asl
->out_count
; i
++)
445 free(asl
->out_list
[i
].mfmt
);
446 free(asl
->out_list
[i
].tfmt
);
451 memset(asl
, 0, sizeof(asl_client_t
));
456 asl_close(aslclient ac
)
458 asl_client_release((asl_client_t
*)ac
);
461 __private_extern__ asl_client_t
*
462 asl_client_retain(asl_client_t
*asl
)
466 if (asl
== NULL
) return NULL
;
468 new = OSAtomicIncrement32(&asl
->refcount
);
474 __private_extern__ asl_client_t
*
477 static dispatch_once_t once
;
479 dispatch_once(&once
, ^{
481 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
482 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
483 * which locks _asl_global.lock.
485 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
487 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
488 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
490 /* Now call _asl_notify_open(0) to finish the work */
494 return _asl_global
.asl
;
498 * asl_add_file: write log messages to the given file descriptor
499 * Log messages will be written to this file as well as to the server.
502 asl_add_output_file(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
)
509 asl
= (asl_client_t
*)ac
;
512 asl
= _asl_open_default();
513 if (asl
== NULL
) return -1;
514 pthread_mutex_lock(&_asl_global
.lock
);
518 for (i
= 0; i
< asl
->out_count
; i
++)
520 if (asl
->out_list
[i
].fd
== fd
)
522 /* update message format, time format, filter, and text encoding */
523 free(asl
->out_list
[i
].mfmt
);
524 asl
->out_list
[i
].mfmt
= NULL
;
525 if (mfmt
!= NULL
) asl
->out_list
[i
].mfmt
= strdup(mfmt
);
527 free(asl
->out_list
[i
].tfmt
);
528 asl
->out_list
[i
].tfmt
= NULL
;
529 if (tfmt
!= NULL
) asl
->out_list
[i
].tfmt
= strdup(tfmt
);
531 asl
->out_list
[i
].encoding
= text_encoding
;
532 asl
->out_list
[i
].filter
= filter
;
534 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
539 if (asl
->out_count
== 0)
541 asl
->out_list
= (asl_out_file_t
*)calloc(1, sizeof(asl_out_file_t
));
545 asl
->out_list
= (asl_out_file_t
*)reallocf(asl
->out_list
, (1 + asl
->out_count
) * sizeof(asl_out_file_t
));
548 if (asl
->out_list
== NULL
)
550 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
554 asl
->out_list
[asl
->out_count
].fd
= fd
;
555 asl
->out_list
[asl
->out_count
].encoding
= text_encoding
;
556 asl
->out_list
[asl
->out_count
].filter
= filter
;
557 if (mfmt
!= NULL
) asl
->out_list
[asl
->out_count
].mfmt
= strdup(mfmt
);
558 if (tfmt
!= NULL
) asl
->out_list
[asl
->out_count
].tfmt
= strdup(tfmt
);
562 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
567 asl_set_output_file_filter(aslclient ac
, int fd
, int filter
)
574 asl
= (asl_client_t
*)ac
;
577 asl
= _asl_open_default();
578 if (asl
== NULL
) return -1;
579 pthread_mutex_lock(&_asl_global
.lock
);
585 for (i
= 0; i
< asl
->out_count
; i
++)
587 if (asl
->out_list
[i
].fd
== fd
)
590 last
= asl
->out_list
[i
].filter
;
591 asl
->out_list
[i
].filter
= filter
;
596 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
600 /* SPI - Deprecated */
602 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
604 return asl_add_output_file(ac
, fd
, mfmt
, tfmt
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), text_encoding
);
608 asl_add_log_file(aslclient ac
, int fd
)
610 return asl_add_output_file(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), ASL_ENCODE_SAFE
);
614 * asl_remove_output: stop writing log messages to the given file descriptor
617 asl_remove_output_file(aslclient ac
, int fd
)
620 int x
, use_global_lock
;
624 asl
= (asl_client_t
*)ac
;
627 asl
= _asl_open_default();
628 if (asl
== NULL
) return -1;
629 pthread_mutex_lock(&_asl_global
.lock
);
633 if (asl
->out_count
== 0)
635 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
640 for (i
= 0; i
< asl
->out_count
; i
++)
642 if (asl
->out_list
[i
].fd
== fd
)
651 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
655 free(asl
->out_list
[x
].mfmt
);
656 free(asl
->out_list
[x
].tfmt
);
658 for (i
= x
+ 1; i
< asl
->out_count
; i
++, x
++)
660 asl
->out_list
[x
] = asl
->out_list
[i
];
665 if (asl
->out_count
== 0)
668 asl
->out_list
= NULL
;
672 asl
->out_list
= (asl_out_file_t
*)reallocf(asl
->out_list
, asl
->out_count
* sizeof(asl_out_file_t
));
674 if (asl
->out_list
== NULL
)
677 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
682 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
687 asl_remove_output(aslclient ac
, int fd
)
689 return asl_remove_output_file(ac
, fd
);
693 asl_remove_log_file(aslclient ac
, int fd
)
695 return asl_remove_output_file(ac
, fd
);
699 asl_set_filter(aslclient ac
, int f
)
701 int last
, use_global_lock
;
705 asl
= (asl_client_t
*)ac
;
708 asl
= _asl_open_default();
709 if (asl
== NULL
) return -1;
710 pthread_mutex_lock(&_asl_global
.lock
);
717 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
722 * Evaluate client / message / level to determine what to do with a message.
723 * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message
724 * can be ignored. Otherwise it returns the bits below, ORed with the level.
726 * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
727 * EVAL_SEND - will send to syslogd
728 * EVAL_TUNNEL - will send to syslogd with tunneling enabled
729 * EVAL_FILE - will write to file
732 _asl_evaluate_send(aslclient ac
, aslmsg msg
, int slevel
)
734 asl_client_t
*asl
= (asl_client_t
*)ac
;
735 uint32_t level
, lmask
, filter
, status
, tunnel
;
742 asl
= _asl_open_default();
743 if (asl
== NULL
) return EVAL_IGNORE
;
746 check
= ASL_LEVEL_DEBUG
;
747 if (slevel
>= 0) check
= slevel
;
749 val
= asl_get((aslmsg
)msg
, ASL_KEY_LEVEL
);
750 if (val
!= NULL
) check
= atoi(val
);
752 if (check
< ASL_LEVEL_EMERG
) check
= ASL_LEVEL_EMERG
;
753 else if (check
> ASL_LEVEL_DEBUG
) check
= ASL_LEVEL_DEBUG
;
758 if (asl
->aslfile
!= NULL
) return (out
| EVAL_ASLFILE
);
760 lmask
= ASL_FILTER_MASK(level
);
762 filter
= asl
->filter
& 0xff;
763 tunnel
= (asl
->filter
& ASL_FILTER_MASK_TUNNEL
) >> 8;
765 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
767 pthread_mutex_lock(&_asl_global
.lock
);
769 if (_asl_global
.rc_change_token
>= 0)
771 /* initialize or re-check process-specific and master filters */
773 status
= notify_check(_asl_global
.rc_change_token
, &check
);
774 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
776 if (_asl_global
.master_token
>= 0)
779 status
= notify_get_state(_asl_global
.master_token
, &v64
);
780 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
783 if (_asl_global
.notify_token
>= 0)
786 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
787 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
792 pthread_mutex_unlock(&_asl_global
.lock
);
794 /* master filter overrides local filter */
795 if (_asl_global
.master_filter
!= 0)
797 filter
= _asl_global
.master_filter
;
801 /* process-specific filter overrides local and master */
802 if (_asl_global
.proc_filter
!= 0)
804 filter
= _asl_global
.proc_filter
;
809 if ((filter
!= 0) && ((filter
& lmask
) != 0))
812 if (tunnel
!= 0) out
|= EVAL_TUNNEL
;
813 if (asl
->out_count
> 0) out
|= EVAL_FILE
;
818 if ((asl
->options
& ASL_OPT_SYSLOG_LEGACY
) && (filter
!= 0) && ((filter
& lmask
) == 0))
823 if (asl
->out_count
> 0) return (out
| EVAL_FILE
);
828 #endif /* BUILDING_VARIANT */
832 * Internal routine used by asl_vlog.
834 * eval: log level and send flags for the message
835 * format: A formating string
836 * ap: va_list for the format
837 * returns 0 for success, non-zero for failure
840 _asl_lib_vlog(aslclient ac
, uint32_t eval
, aslmsg msg
, const char *format
, va_list ap
)
842 int saved_errno
= errno
;
844 char *str
, *fmt
, estr
[NL_TEXTMAX
];
845 uint32_t i
, len
, elen
, expand
;
848 asl
= (asl_client_t
*)ac
;
852 * Initialize _asl_global so that asl_new will have global data.
853 * Not strictly necessary, but helps performance.
855 asl
= _asl_open_default();
856 if (asl
== NULL
) return -1;
859 if (format
== NULL
) return -1;
861 /* insert strerror for %m */
866 for (i
= 0; format
[i
] != '\0'; i
++)
868 if (format
[i
] == '%')
870 if (format
[i
+1] == '\0') len
++;
871 else if (format
[i
+1] == 'm')
874 strerror_r(saved_errno
, estr
, sizeof(estr
));
888 fmt
= (char *)format
;
892 fmt
= malloc(len
+ 1);
895 if (estr
!= NULL
) free(estr
);
901 for (i
= 0; format
[i
] != '\0'; i
++)
903 if (format
[i
] == '%')
905 if (format
[i
+1] == '\0')
908 else if ((format
[i
+1] == 'm') && (elen
!= 0))
910 memcpy(fmt
+len
, estr
, elen
);
916 fmt
[len
++] = format
[i
++];
917 fmt
[len
++] = format
[i
];
920 else fmt
[len
++] = format
[i
];
927 vasprintf(&str
, fmt
, ap
);
928 if (expand
!= 0) free(fmt
);
930 if (str
== NULL
) return -1;
932 status
= _asl_send_message(ac
, eval
, (asl_msg_t
*)msg
, str
);
940 * Similar to asl_log, but take a va_list instead of a list of arguments.
942 * level: the log level of the associated message
943 * format: A formating string
944 * ap: va_list for the format
945 * returns 0 for success, non-zero for failure
948 asl_vlog(aslclient ac
, aslmsg msg
, int level
, const char *format
, va_list ap
)
950 uint32_t eval
= _asl_evaluate_send(ac
, msg
, level
);
951 if (eval
== EVAL_IGNORE
) return 0;
953 return _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
958 * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
959 * forwards the call to _asl_lib_vlog.
961 * eval: log level and send flags for the message
962 * format: A formating string
963 * ... args for format
964 * returns 0 for success, non-zero for failure
967 _asl_lib_log(aslclient ac
, uint32_t eval
, aslmsg msg
, const char *format
, ...)
970 if (eval
== EVAL_IGNORE
) return 0;
973 va_start(ap
, format
);
974 status
= _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
982 * Processes an ASL log message.
984 * level: the log level of the associated message
985 * format: A formating string
986 * ... args for format
987 * returns 0 for success, non-zero for failure
990 asl_log(aslclient ac
, aslmsg msg
, int level
, const char *format
, ...)
993 uint32_t eval
= _asl_evaluate_send(ac
, msg
, level
);
994 if (eval
== EVAL_IGNORE
) return 0;
997 va_start(ap
, format
);
998 status
= _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
1004 #ifndef BUILDING_VARIANT
1007 * asl_get_filter: gets the values for the local, master, and remote filters,
1008 * and indicates which one is active.
1011 asl_get_filter(aslclient ac
, int *local
, int *master
, int *remote
, int *active
)
1013 asl_client_t
*asl
, *asl_default
;
1023 asl_default
= _asl_open_default();
1025 asl
= (asl_client_t
*)ac
;
1026 if (asl
== NULL
) asl
= asl_default
;
1027 if (asl
!= NULL
) l
= asl
->filter
& 0xff;
1029 if ((asl_default
!= NULL
) && (!(asl_default
->options
& ASL_OPT_NO_REMOTE
)))
1031 pthread_mutex_lock(&_asl_global
.lock
);
1033 if (_asl_global
.rc_change_token
>= 0)
1035 /* initialize or re-check process-specific and master filters */
1037 status
= notify_check(_asl_global
.rc_change_token
, &check
);
1038 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
1040 if (_asl_global
.master_token
>= 0)
1043 status
= notify_get_state(_asl_global
.master_token
, &v64
);
1044 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
1047 if (_asl_global
.notify_token
>= 0)
1050 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
1051 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
1056 m
= _asl_global
.master_filter
;
1059 r
= _asl_global
.proc_filter
;
1062 pthread_mutex_unlock(&_asl_global
.lock
);
1065 if (local
!= NULL
) *local
= l
;
1066 if (master
!= NULL
) *master
= m
;
1067 if (remote
!= NULL
) *remote
= r
;
1068 if (active
!= NULL
) *active
= x
;
1074 _asl_send_message(aslclient ac
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
)
1076 uint32_t i
, len
, level
, lmask
, outstatus
;
1080 struct timeval tval
;
1083 int use_global_lock
;
1084 kern_return_t kstatus
;
1086 char aux_host
[_POSIX_HOST_NAME_MAX
];
1089 if (eval
== EVAL_IGNORE
) return 0;
1091 level
= eval
& LEVEL_MASK
;
1093 lmask
= ASL_FILTER_MASK(level
);
1095 use_global_lock
= 0;
1096 asl
= (asl_client_t
*)ac
;
1099 asl
= _asl_open_default();
1100 if (asl
== NULL
) return -1;
1101 use_global_lock
= 1;
1104 if (asl
->aslfile
!= NULL
) use_global_lock
= 1;
1107 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here.
1108 * Also sets Sender & Facility (if unset) and "ASLOption store" if remote control is active.
1110 aux
= asl_msg_new(ASL_TYPE_MSG
);
1112 if (mstring
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstring
);
1114 snprintf(aux_val
, sizeof(aux_val
), "%u", level
);
1115 asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, aux_val
);
1117 memset(&tval
, 0, sizeof(struct timeval
));
1119 status
= gettimeofday(&tval
, NULL
);
1122 snprintf(aux_val
, sizeof(aux_val
), "%lu", tval
.tv_sec
);
1123 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
1124 snprintf(aux_val
, sizeof(aux_val
), "%d", tval
.tv_usec
* 1000);
1125 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
);
1130 snprintf(aux_val
, sizeof(aux_val
), "%lu", tick
);
1131 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
1134 memset(&aux_host
, 0, _POSIX_HOST_NAME_MAX
);
1135 if (gethostname(aux_host
, _POSIX_HOST_NAME_MAX
) == 0)
1137 asl_msg_set_key_val(aux
, ASL_KEY_HOST
, aux_host
);
1140 snprintf(aux_val
, sizeof(aux_val
), "%u", getpid());
1141 asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
);
1143 snprintf(aux_val
, sizeof(aux_val
), "%d", getuid());
1144 asl_msg_set_key_val(aux
, ASL_KEY_UID
, aux_val
);
1146 snprintf(aux_val
, sizeof(aux_val
), "%d", getgid());
1147 asl_msg_set_key_val(aux
, ASL_KEY_GID
, aux_val
);
1150 * Set Sender if needed
1152 status
= asl_msg_lookup((asl_msg_t
*)msg
, ASL_KEY_SENDER
, &val
, NULL
);
1153 if ((status
!= 0) || (val
== NULL
))
1155 if ((ac
!= NULL
) && (ac
->name
!= NULL
))
1157 /* Use the Sender name from the client handle */
1158 asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, ac
->name
);
1162 /* Get the value for ASL_KEY_SENDER from cache */
1163 if (_asl_global
.sender
== NULL
)
1165 name
= *(*_NSGetArgv());
1168 x
= strrchr(name
, '/');
1172 pthread_mutex_lock(&_asl_global
.lock
);
1173 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
1174 pthread_mutex_unlock(&_asl_global
.lock
);
1178 if (_asl_global
.sender
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
);
1179 else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown");
1186 status
= asl_msg_lookup((asl_msg_t
*)msg
, ASL_KEY_FACILITY
, &val
, NULL
);
1187 if ((status
!= 0) || (val
== NULL
))
1189 if ((ac
!= NULL
) && (ac
->facility
!= NULL
))
1191 /* Use the Facility name from the client handle */
1192 asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, ac
->facility
);
1196 /* Set "ASLOption store" if tunneling */
1198 if (eval
& EVAL_TUNNEL
)
1200 val
= asl_get((aslmsg
)msg
, ASL_KEY_OPTION
);
1203 asl_msg_set_key_val(aux
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
1207 char *aux_option
= NULL
;
1208 asprintf(&aux_option
, "%s %s", ASL_OPT_STORE
, val
);
1209 asl_msg_set_key_val(aux
, ASL_KEY_OPTION
, aux_option
);
1216 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
1218 aux
= asl_msg_merge(aux
, msg
);
1221 * If there is an aslfile this is a stand-alone file client.
1222 * Just save to the file.
1224 if (asl
->aslfile
!= NULL
)
1226 outstatus
= ASL_STATUS_FAILED
;
1230 outstatus
= asl_file_save(asl
->aslfile
, (aslmsg
)aux
, &(asl
->aslfileid
));
1234 asl_msg_release(aux
);
1236 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1244 if ((eval
& EVAL_TUNNEL
) == 0)
1246 time_t last_send
= _asl_global
.last_send
;
1247 time_t last_oq
= _asl_global
.last_oq_msg
;
1248 uint32_t qcurr
= _asl_global
.quota
;
1250 uint32_t qinc
, qnew
;
1254 /* add QUOTA_MPS to quota for each second we've been idle */
1255 if (tval
.tv_sec
> last_send
)
1257 delta
= tval
.tv_sec
- last_send
;
1260 if (delta
< (QUOTA_MPH
/ QUOTA_MPS
)) qinc
= delta
* QUOTA_MPS
;
1262 qnew
= MIN(QUOTA_MPH
, qcurr
+ qinc
);
1263 OSAtomicCompareAndSwapLongBarrier(last_send
, tval
.tv_sec
, (long *)&_asl_global
.last_send
);
1268 if ((tval
.tv_sec
- last_oq
) > QUOTA_MSG_INTERVAL
)
1271 OSAtomicCompareAndSwapLongBarrier(last_oq
, tval
.tv_sec
, (long *)&_asl_global
.last_oq_msg
);
1280 OSAtomicCompareAndSwap32Barrier(qcurr
, qnew
- 1, (int32_t *)&_asl_global
.quota
);
1284 if ((_asl_global
.server_port
!= MACH_PORT_NULL
) && (eval
& EVAL_SEND
))
1286 asl_string_t
*send_str
;
1290 if (eval
& EVAL_QUOTA
)
1292 asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, QUOTA_LEVEL
);
1293 asl_msg_set_key_val(aux
, ASL_KEY_MSG
, QUOTA_MSG
);
1296 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw");
1297 len
= asl_string_length(send_str
);
1298 vmsize
= asl_string_allocated_size(send_str
);
1299 str
= asl_string_free_return_bytes(send_str
);
1303 /* send a mach message to syslogd */
1304 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1305 if (kstatus
!= KERN_SUCCESS
)
1307 /* retry once if the call failed */
1308 _asl_global_reset();
1310 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1311 if (kstatus
!= KERN_SUCCESS
)
1313 _asl_global_reset();
1314 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1319 else if (vmsize
>0) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1322 if ((aux
!= NULL
) && (asl
->out_count
> 0))
1324 /* write to file descriptors */
1325 for (i
= 0; i
< asl
->out_count
; i
++)
1327 if ((asl
->out_list
[i
].fd
>= 0) && (asl
->out_list
[i
].filter
!= 0) && ((asl
->out_list
[i
].filter
& lmask
) != 0))
1332 str
= asl_format_message(aux
, asl
->out_list
[i
].mfmt
, asl
->out_list
[i
].tfmt
, asl
->out_list
[i
].encoding
, &len
);
1333 if (str
== NULL
) continue;
1335 status
= write(asl
->out_list
[i
].fd
, str
, len
- 1);
1338 /* soft error for fd 2 (stderr) */
1339 if (asl
->out_list
[i
].fd
!= 2) outstatus
= -1;
1340 asl
->out_list
[i
].fd
= -1;
1348 asl_msg_release(aux
);
1350 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1356 * asl_send: send a message
1357 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1358 * has been used to set all of a message's attributes.
1359 * eval: hints about what to do with the message
1361 * returns 0 for success, non-zero for failure
1364 asl_send(aslclient ac
, aslmsg msg
)
1367 uint32_t eval
= _asl_evaluate_send(ac
, msg
, -1);
1368 if (eval
!= 0) status
= _asl_send_message(ac
, eval
, (asl_msg_t
*)msg
, NULL
);
1374 _asl_aux_save_context(asl_aux_context_t
*ctx
)
1376 if (ctx
== NULL
) return -1;
1378 pthread_mutex_lock(&_asl_global
.lock
);
1380 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count
+ 1) * sizeof(asl_aux_context_t
*));
1381 if (_asl_global
.aux_ctx
== NULL
)
1383 _asl_global
.aux_count
= 0;
1387 _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
;
1389 pthread_mutex_unlock(&_asl_global
.lock
);
1395 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1396 * will be saved at the time that the auxiliary file is created. The message will include
1397 * any keys and values found in msg, and it will include the title and Uniform Type
1398 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1399 * new auxiliary file.
1402 _asl_auxiliary(asl_msg_t
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
)
1405 asl_string_t
*send_str
;
1407 fileport_t fileport
;
1408 kern_return_t kstatus
;
1410 uint32_t newurllen
, where
;
1411 int status
, fd
, fdpair
[2];
1413 dispatch_queue_t pipe_q
;
1414 dispatch_io_t pipe_channel
;
1415 dispatch_semaphore_t sem
;
1417 aux
= asl_msg_new(ASL_TYPE_MSG
);
1421 asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
);
1426 asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data");
1430 asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
);
1435 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
);
1438 aux
= asl_msg_merge(aux
, msg
);
1440 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1443 uint32_t eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux
, -1);
1444 status
= _asl_send_message(NULL
, eval
, aux
, NULL
);
1445 asl_msg_release(aux
);
1449 where
= asl_store_location();
1451 if (where
== ASL_STORE_LOCATION_MEMORY
)
1455 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1456 if (ctx
== NULL
) return -1;
1458 status
= pipe(fdpair
);
1465 /* give read end to dispatch_io_read */
1467 sem
= dispatch_semaphore_create(0);
1469 ctx
->fd
= fdpair
[1];
1471 status
= _asl_aux_save_context(ctx
);
1476 dispatch_release(sem
);
1481 pipe_q
= dispatch_queue_create("PipeQ", NULL
);
1482 pipe_channel
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){
1486 *out_fd
= fdpair
[1];
1488 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
);
1490 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){
1493 size_t len
= dispatch_data_get_size(pipedata
);
1496 const char *bytes
= NULL
;
1500 dispatch_data_t md
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
);
1501 encoded
= asl_core_encode_buffer(bytes
, len
);
1502 asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
);
1504 eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux
, -1);
1505 _asl_send_message(NULL
, eval
, aux
, NULL
);
1506 asl_msg_release(aux
);
1507 dispatch_release(md
);
1513 dispatch_semaphore_signal(sem
);
1514 dispatch_release(pipe_channel
);
1515 dispatch_release(pipe_q
);
1523 if (_asl_global
.server_port
== MACH_PORT_NULL
) return -1;
1525 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw");
1526 len
= asl_string_length(send_str
);
1527 vmsize
= asl_string_allocated_size(send_str
);
1528 str
= asl_string_free_return_bytes(send_str
);
1532 asl_msg_release(aux
);
1533 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1538 fileport
= MACH_PORT_NULL
;
1539 status
= KERN_SUCCESS
;
1541 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1542 if (kstatus
!= KERN_SUCCESS
)
1544 /* retry once if the call failed */
1545 _asl_global_reset();
1547 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1548 if (kstatus
!= KERN_SUCCESS
)
1550 _asl_global_reset();
1551 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1552 asl_msg_release(aux
);
1559 asl_msg_release(aux
);
1565 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
);
1566 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
);
1569 if (fileport
== MACH_PORT_NULL
)
1571 asl_msg_release(aux
);
1575 fd
= fileport_makefd(fileport
);
1576 mach_port_deallocate(mach_task_self(), fileport
);
1579 asl_msg_release(aux
);
1584 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1596 status
= _asl_aux_save_context(ctx
);
1604 asl_create_auxiliary_file(aslmsg msg
, const char *title
, const char *uti
, int *out_fd
)
1606 if (out_fd
== NULL
) return -1;
1608 return _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, NULL
, out_fd
);
1612 asl_log_auxiliary_location(aslmsg msg
, const char *title
, const char *uti
, const char *url
)
1614 return _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, url
, NULL
);
1618 * Close an auxiliary file.
1619 * Sends the cached auxiliary message to syslogd.
1622 asl_close_auxiliary_file(int fd
)
1626 dispatch_semaphore_t aux_sem
= NULL
;
1628 pthread_mutex_lock(&(_asl_global
.lock
));
1633 for (i
= 0; i
< _asl_global
.aux_count
; i
++)
1635 if (_asl_global
.aux_ctx
[i
]->fd
== fd
)
1639 aux_msg
= _asl_global
.aux_ctx
[i
]->msg
;
1640 aux_sem
= _asl_global
.aux_ctx
[i
]->sem
;
1642 free(_asl_global
.aux_ctx
[i
]);
1644 for (j
= i
+ 1; j
< _asl_global
.aux_count
; i
++, j
++)
1646 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
];
1649 _asl_global
.aux_count
--;
1651 if (_asl_global
.aux_count
== 0)
1653 free(_asl_global
.aux_ctx
);
1654 _asl_global
.aux_ctx
= NULL
;
1658 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count
* sizeof(asl_aux_context_t
*));
1659 if (_asl_global
.aux_ctx
== NULL
)
1661 _asl_global
.aux_count
= 0;
1670 pthread_mutex_unlock(&(_asl_global
.lock
));
1674 if (aux_msg
!= NULL
)
1676 uint32_t eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux_msg
, -1);
1677 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status
= -1;
1678 asl_msg_release(aux_msg
);
1681 if (aux_sem
!= NULL
)
1683 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
);
1684 dispatch_release(aux_sem
);
1691 * asl_search: Search for messages matching the criteria described
1692 * by the aslmsg. The caller should set the attributes to match using
1693 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
1694 * used for attributes set with asl_set().
1696 * returns: a set of messages that can be iterated over using aslresp_next(),
1697 * and the values can be retrieved using aslresp_get.
1701 * This routine searches the ASL datastore on disk (/var/log/asl).
1702 * It is called my asl_search if syslogd is not running or if syslogd
1703 * indicates that an in-memory store is not being used.
1706 _asl_search_store(aslclient ac
, aslmsg a
)
1708 asl_search_result_t query
, *out
;
1709 asl_msg_t
*q
, *qlist
[1];
1710 uint32_t status
, op
;
1711 uint64_t last_id
, start_id
;
1715 if (a
== NULL
) return NULL
;
1719 /* check for "ASLMessageId >[=] n" and set start_id */
1723 status
= asl_msg_lookup(q
, ASL_KEY_MSG_ID
, &val
, &op
);
1724 if ((status
== 0) && (val
!= NULL
) && (op
& ASL_QUERY_OP_GREATER
))
1726 if (op
& ASL_QUERY_OP_EQUAL
) start_id
= atoll(val
);
1727 else start_id
= atoll(val
) + 1;
1731 status
= asl_store_open_read(NULL
, &store
);
1732 if (status
!= 0) return NULL
;
1733 if (store
== NULL
) return NULL
;
1738 qlist
[0] = (asl_msg_t
*)a
;
1739 memset(&query
, 0, sizeof(asl_search_result_t
));
1743 status
= asl_store_match(store
, &query
, &out
, &last_id
, start_id
, 0, 1);
1744 asl_store_close(store
);
1750 _asl_search_concat_results(asl_search_result_t
*batch
, asl_search_result_t
**out
)
1754 if (out
== NULL
) return ASL_STATUS_FAILED
;
1756 /* nothing to do if batch is NULL or contains no messages */
1757 if (batch
== NULL
) return 0;
1758 if (batch
->count
== 0)
1760 aslresponse_free(batch
);
1764 if (*out
== NULL
) *out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1767 aslresponse_free(batch
);
1768 return ASL_STATUS_FAILED
;
1771 if ((*out
)->count
== 0)
1773 (*out
)->msg
= (asl_msg_t
**)calloc(batch
->count
, sizeof(asl_msg_t
*));
1777 (*out
)->msg
= (asl_msg_t
**)reallocf((*out
)->msg
, ((*out
)->count
+ batch
->count
) * sizeof(asl_msg_t
*));
1780 if ((*out
)->msg
== NULL
)
1782 aslresponse_free(batch
);
1785 return ASL_STATUS_FAILED
;
1788 for (i
= 0, j
= (*out
)->count
; i
< batch
->count
; i
++, j
++) (*out
)->msg
[j
] = batch
->msg
[i
];
1790 (*out
)->count
+= batch
->count
;
1793 return ASL_STATUS_OK
;
1797 _asl_search_memory(aslclient ac
, aslmsg a
)
1799 asl_search_result_t
*batch
, *out
;
1800 char *qstr
, *str
, *res
;
1801 uint32_t len
, reslen
, status
;
1802 uint64_t cmax
, qmin
;
1803 kern_return_t kstatus
;
1806 if (a
== NULL
) return 0;
1809 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1812 qstr
= asl_msg_to_string((asl_msg_t
*)a
, &len
);
1817 asprintf(&str
, "0\n");
1822 asprintf(&str
, "1\n%s\n", qstr
);
1827 if (str
== NULL
) return NULL
;
1830 * Fetch a batch of results each time through the loop.
1831 * Fetching small batches rebuces the load on syslogd.
1841 status
= ASL_STATUS_OK
;
1843 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
1844 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1846 memmove(vmstr
, str
, len
);
1849 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1850 if (kstatus
!= KERN_SUCCESS
)
1852 /* retry once if the call failed */
1853 _asl_global_reset();
1855 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1856 if (kstatus
!= KERN_SUCCESS
)
1858 _asl_global_reset();
1863 if (res
== NULL
) break;
1865 batch
= asl_list_from_string(res
);
1866 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1868 status
= _asl_search_concat_results(batch
, &out
);
1869 if (status
!= ASL_STATUS_OK
) break;
1870 if ((out
== NULL
) || (out
->count
< FETCH_BATCH
)) break;
1872 if (cmax
>= qmin
) qmin
= cmax
+ 1;
1881 _asl_server_control_query(void)
1883 asl_search_result_t
*list
= NULL
;
1885 uint32_t len
, reslen
, status
;
1886 uint64_t cmax
, qmin
;
1887 kern_return_t kstatus
;
1889 asl_msg_t
*m
= NULL
;
1890 static const char ctlstr
[] = "1\nQ [= ASLOption control]\n";
1893 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1895 len
= strlen(ctlstr
) + 1;
1902 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
1903 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1905 memmove(vmstr
, ctlstr
, len
);
1908 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1909 if (kstatus
!= KERN_SUCCESS
)
1911 /* retry once if the call failed */
1912 _asl_global_reset();
1914 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1915 if (kstatus
!= KERN_SUCCESS
) _asl_global_reset();
1918 list
= asl_list_from_string(res
);
1919 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1921 if (list
== NULL
) return NULL
;
1922 if (list
->count
> 0) m
= asl_msg_retain(list
->msg
[0]);
1923 aslresponse_free((aslresponse
)list
);
1928 asl_store_location()
1930 kern_return_t kstatus
;
1932 uint32_t reslen
, status
;
1936 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
1941 status
= ASL_STATUS_OK
;
1943 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1944 if (kstatus
!= KERN_SUCCESS
)
1946 /* retry once if the call failed */
1947 _asl_global_reset();
1949 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1952 /* res should never be returned, but just to be certain we don't leak VM ... */
1953 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1955 if (kstatus
!= KERN_SUCCESS
)
1957 _asl_global_reset();
1958 return ASL_STORE_LOCATION_FILE
;
1961 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
1962 return ASL_STORE_LOCATION_FILE
;
1966 asl_search(aslclient ac
, aslmsg a
)
1969 asl_search_result_t
*out
;
1973 where
= asl_store_location();
1974 if (where
== ASL_STORE_LOCATION_FILE
) out
= _asl_search_store(ac
, a
);
1975 else out
= _asl_search_memory(ac
, a
);
1981 asl_syslog_faciliy_name_to_num(const char *name
)
1983 if (name
== NULL
) return -1;
1985 if (strcaseeq(name
, "auth")) return LOG_AUTH
;
1986 if (strcaseeq(name
, "authpriv")) return LOG_AUTHPRIV
;
1987 if (strcaseeq(name
, "cron")) return LOG_CRON
;
1988 if (strcaseeq(name
, "daemon")) return LOG_DAEMON
;
1989 if (strcaseeq(name
, "ftp")) return LOG_FTP
;
1990 if (strcaseeq(name
, "install")) return LOG_INSTALL
;
1991 if (strcaseeq(name
, "kern")) return LOG_KERN
;
1992 if (strcaseeq(name
, "lpr")) return LOG_LPR
;
1993 if (strcaseeq(name
, "mail")) return LOG_MAIL
;
1994 if (strcaseeq(name
, "netinfo")) return LOG_NETINFO
;
1995 if (strcaseeq(name
, "remoteauth")) return LOG_REMOTEAUTH
;
1996 if (strcaseeq(name
, "news")) return LOG_NEWS
;
1997 if (strcaseeq(name
, "security")) return LOG_AUTH
;
1998 if (strcaseeq(name
, "syslog")) return LOG_SYSLOG
;
1999 if (strcaseeq(name
, "user")) return LOG_USER
;
2000 if (strcaseeq(name
, "uucp")) return LOG_UUCP
;
2001 if (strcaseeq(name
, "local0")) return LOG_LOCAL0
;
2002 if (strcaseeq(name
, "local1")) return LOG_LOCAL1
;
2003 if (strcaseeq(name
, "local2")) return LOG_LOCAL2
;
2004 if (strcaseeq(name
, "local3")) return LOG_LOCAL3
;
2005 if (strcaseeq(name
, "local4")) return LOG_LOCAL4
;
2006 if (strcaseeq(name
, "local5")) return LOG_LOCAL5
;
2007 if (strcaseeq(name
, "local6")) return LOG_LOCAL6
;
2008 if (strcaseeq(name
, "local7")) return LOG_LOCAL7
;
2009 if (strcaseeq(name
, "launchd")) return LOG_LAUNCHD
;
2015 asl_syslog_faciliy_num_to_name(int n
)
2017 if (n
< 0) return NULL
;
2019 if (n
== LOG_AUTH
) return "auth";
2020 if (n
== LOG_AUTHPRIV
) return "authpriv";
2021 if (n
== LOG_CRON
) return "cron";
2022 if (n
== LOG_DAEMON
) return "daemon";
2023 if (n
== LOG_FTP
) return "ftp";
2024 if (n
== LOG_INSTALL
) return "install";
2025 if (n
== LOG_KERN
) return "kern";
2026 if (n
== LOG_LPR
) return "lpr";
2027 if (n
== LOG_MAIL
) return "mail";
2028 if (n
== LOG_NETINFO
) return "netinfo";
2029 if (n
== LOG_REMOTEAUTH
) return "remoteauth";
2030 if (n
== LOG_NEWS
) return "news";
2031 if (n
== LOG_AUTH
) return "security";
2032 if (n
== LOG_SYSLOG
) return "syslog";
2033 if (n
== LOG_USER
) return "user";
2034 if (n
== LOG_UUCP
) return "uucp";
2035 if (n
== LOG_LOCAL0
) return "local0";
2036 if (n
== LOG_LOCAL1
) return "local1";
2037 if (n
== LOG_LOCAL2
) return "local2";
2038 if (n
== LOG_LOCAL3
) return "local3";
2039 if (n
== LOG_LOCAL4
) return "local4";
2040 if (n
== LOG_LOCAL5
) return "local5";
2041 if (n
== LOG_LOCAL6
) return "local6";
2042 if (n
== LOG_LOCAL7
) return "local7";
2043 if (n
== LOG_LAUNCHD
) return "launchd";
2049 * utility for converting a time string into a time_t
2050 * we only deal with the following formats:
2051 * Canonical form YYYY.MM.DD hh:mm:ss UTC
2052 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
2053 * absolute form - # seconds since the epoch (e.g. 1095789191)
2054 * relative time - seconds before or after now (e.g. -300, +43200)
2055 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
2058 #define CANONICAL_TIME_REX "^[0-9][0-9][0-9][0-9].[01]?[0-9].[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9][ ]+UTC$"
2059 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
2060 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
2061 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
2063 #define SECONDS_PER_MINUTE 60
2064 #define SECONDS_PER_HOUR 3600
2065 #define SECONDS_PER_DAY 86400
2066 #define SECONDS_PER_WEEK 604800
2068 static regex_t rex_canon
, rex_ctime
, rex_abs
, rex_rel
;
2069 static int reg_status
= 0;
2072 * We use the last letter in the month name to determine
2073 * the month number (0-11). There are two collisions:
2074 * Jan and Jun both end in n
2075 * Mar and Apr both end in r
2076 * In these cases we check the second letter.
2078 * The MTH_LAST array maps the last letter to a number.
2080 static const int8_t MTH_LAST
[] = {-1, 1, 11, -1, -1, -1, 7, -1, -1, -1, -1, 6, -1, 5, -1, 8, -1, 3, -1, 9, -1, 10, -1, -1, 4, -1};
2089 if (s
[2] > 90) v8
= s
[2] - 'a';
2090 else v8
= s
[2] - 'A';
2092 if ((v8
< 0) || (v8
> 25)) return -1;
2095 if (v8
< 0) return -1;
2098 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
2099 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
2104 asl_parse_time(const char *in
)
2108 time_t tick
, delta
, factor
;
2110 static dispatch_once_t once
;
2112 if (in
== NULL
) return -1;
2114 dispatch_once(&once
, ^{
2116 int rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
2118 memset(&rex_canon
, 0, sizeof(regex_t
));
2119 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
2120 if (status
!= 0) reg_status
= -1;
2122 memset(&rex_ctime
, 0, sizeof(regex_t
));
2123 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
2124 if (status
!= 0) reg_status
= -1;
2126 memset(&rex_abs
, 0, sizeof(regex_t
));
2127 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
2128 if (status
!= 0) reg_status
= -1;
2130 memset(&rex_rel
, 0, sizeof(regex_t
));
2131 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
2132 if (status
!= 0) reg_status
= -1;
2135 if (reg_status
< 0) return -1;
2137 len
= strlen(in
) + 1;
2139 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
2142 * Absolute time (number of seconds since the epoch)
2145 if (str
== NULL
) return -1;
2147 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
2154 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
2157 * Reletive time (number of seconds before or after right now)
2160 if (str
== NULL
) return -1;
2164 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
2168 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
2171 factor
= SECONDS_PER_MINUTE
;
2173 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
2176 factor
= SECONDS_PER_HOUR
;
2178 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
2181 factor
= SECONDS_PER_DAY
;
2183 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
2186 factor
= SECONDS_PER_WEEK
;
2190 delta
= factor
* atol(str
);
2197 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
2199 memset(&t
, 0, sizeof(struct tm
));
2201 if (str
== NULL
) return -1;
2207 t
.tm_year
= atoi(x
) - 1900;
2213 t
.tm_mon
= atoi(x
) - 1;
2219 t
.tm_mday
= atoi(x
);
2222 for (x
= p
+ 1; *x
== ' '; x
++);
2225 t
.tm_hour
= atoi(x
);
2242 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
2244 /* We assume it's in the current year */
2245 memset(&t
, 0, sizeof(struct tm
));
2247 gmtime_r(&tick
, &t
);
2250 memset(&t
, 0, sizeof(struct tm
));
2252 if (str
== NULL
) return -1;
2255 t
.tm_mon
= _month_num(str
);
2256 if (t
.tm_mon
< 0) return -1;
2258 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
2261 t
.tm_mday
= atoi(x
);
2264 for (x
= p
+ 1; *x
== ' '; x
++);
2267 t
.tm_hour
= atoi(x
);
2288 #endif /* BUILDING_VARIANT */