2 * Copyright (c) 2004-2011 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>
49 #include <dispatch/dispatch.h>
50 #include <libkern/OSAtomic.h>
54 #include "asl_store.h"
55 #include "asl_private.h"
57 #define streq(A, B) (strcmp(A, B) == 0)
58 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
60 #define forever for(;;)
62 #define FETCH_BATCH 256
64 #define LEVEL_MASK 0x0000000f
65 #define EVAL_MASK 0x000000f0
66 #define EVAL_IGNORE 0x00000000
67 #define EVAL_ASLFILE 0x00000010
68 #define EVAL_SEND 0x00000020
69 #define EVAL_TUNNEL 0x00000040
70 #define EVAL_FILE 0x00000080
73 time_t asl_parse_time(const char *);
74 const char *asl_syslog_faciliy_num_to_name(int n
);
75 static int _asl_send_message(aslclient ac
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
);
76 __private_extern__ asl_client_t
*_asl_open_default();
78 /* private asl_file SPI */
79 __private_extern__
uint32_t asl_file_open_write_fd(int fd
, asl_file_t
**s
);
81 /* private asl_msg SPI */
82 __private_extern__ asl_string_t
*asl_msg_to_string_raw(uint32_t encoding
, asl_msg_t
*msg
, int tf
);
85 uint32_t notify_register_plain(const char *name
, int *out_token
);
87 /* fork handling in syslog.c */
88 extern void _syslog_fork_child();
94 dispatch_semaphore_t sem
;
103 uint64_t proc_filter
;
104 uint64_t master_filter
;
105 dispatch_once_t port_lookup_once
;
106 mach_port_t server_port
;
108 pthread_mutex_t lock
;
110 asl_aux_context_t
**aux_ctx
;
115 #ifndef BUILDING_VARIANT
116 __private_extern__ _asl_global_t _asl_global
= {0, -1, -1, -1, 0LL, 0LL, 0, MACH_PORT_NULL
, NULL
, PTHREAD_MUTEX_INITIALIZER
, 0, NULL
, NULL
};
118 #define ASL_SERVICE_NAME "com.apple.system.logger"
121 * Called from the child process inside fork() to clean up
122 * inherited state from the parent process.
124 * NB. A lock isn't required, since we're single threaded in this call.
126 __private_extern__
void
129 _asl_global
.notify_count
= 0;
130 _asl_global
.rc_change_token
= -1;
131 _asl_global
.master_token
= -1;
132 _asl_global
.notify_token
= -1;
134 _asl_global
.port_lookup_once
= 0;
135 _asl_global
.server_port
= MACH_PORT_NULL
;
137 pthread_mutex_init(&(_asl_global
.lock
), NULL
);
141 * asl_remote_notify_name: returns the notification key for remote-control filter
142 * changes for this process.
145 asl_remote_notify_name()
147 pid_t pid
= getpid();
148 uid_t euid
= geteuid();
151 if (euid
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
);
152 else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
);
158 _asl_notify_open(int do_lock
)
163 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
165 _asl_global
.notify_count
++;
167 if (_asl_global
.notify_token
!= -1)
169 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
173 if (_asl_global
.rc_change_token
== -1)
175 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
176 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
179 if (_asl_global
.master_token
== -1)
181 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
182 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
185 notify_name
= asl_remote_notify_name();
186 if (notify_name
!= NULL
)
188 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
190 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
193 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
195 if (_asl_global
.notify_token
== -1) return -1;
202 pthread_mutex_lock(&_asl_global
.lock
);
204 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
206 if (_asl_global
.notify_count
> 0)
208 pthread_mutex_unlock(&_asl_global
.lock
);
212 if (_asl_global
.rc_change_token
>= 0) notify_cancel(_asl_global
.rc_change_token
);
213 _asl_global
.rc_change_token
= -1;
215 if (_asl_global
.master_token
>= 0) notify_cancel(_asl_global
.master_token
);
216 _asl_global
.master_token
= -1;
218 if (_asl_global
.notify_token
>= 0) notify_cancel(_asl_global
.notify_token
);
219 _asl_global
.notify_token
= -1;
221 pthread_mutex_unlock(&_asl_global
.lock
);
227 if (_asl_global
.server_port
== MACH_PORT_NULL
)
229 mach_port_t newport
= MACH_PORT_NULL
;
230 char *str
= getenv("ASL_DISABLE");
231 if ((str
== NULL
) || strcmp(str
, "1"))
233 bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &newport
);
234 if (newport
!= MACH_PORT_NULL
)
236 if (!OSAtomicCompareAndSwap32Barrier(MACH_PORT_NULL
, newport
, (int32_t *)&_asl_global
.server_port
))
238 mach_port_deallocate(mach_task_self(), newport
);
248 mach_port_t tmp
= _asl_global
.server_port
;
249 _asl_global
.server_port
= MACH_PORT_NULL
;
250 mach_port_deallocate(mach_task_self(), tmp
);
254 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
259 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
276 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
280 asl
->name
= strdup(ident
);
281 if (asl
->name
== NULL
)
283 if (asl
->sock
>= 0) close(asl
->sock
);
290 name
= *(*_NSGetArgv());
293 x
= strrchr(name
, '/');
296 asl
->name
= strdup(x
);
297 if (asl
->name
== NULL
)
299 if (asl
->sock
>= 0) close(asl
->sock
);
306 asl
->facility
= NULL
;
307 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
308 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
309 if (asl
->facility
== NULL
)
311 if (asl
->sock
>= 0) close(asl
->sock
);
312 if (asl
->name
!= NULL
) free(asl
->name
);
317 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
319 if (asl
->options
& ASL_OPT_STDERR
) asl_add_output((aslclient
)asl
, fileno(stderr
), ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
323 return (aslclient
)asl
;
327 asl_open_from_file(int fd
, const char *ident
, const char *facility
)
333 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
340 asl
->options
= ASL_OPT_NO_REMOTE
;
347 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
);
351 asl
->name
= strdup(ident
);
352 if (asl
->name
== NULL
)
360 name
= *(*_NSGetArgv());
363 x
= strrchr(name
, '/');
366 asl
->name
= strdup(x
);
367 if (asl
->name
== NULL
)
375 asl
->facility
= NULL
;
376 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
377 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
378 if (asl
->facility
== NULL
)
380 if (asl
->name
!= NULL
) free(asl
->name
);
385 status
= asl_file_open_write_fd(fd
, &(asl
->aslfile
));
386 if (status
!= ASL_STATUS_OK
)
388 if (asl
->name
!= NULL
) free(asl
->name
);
389 if (asl
->facility
!= NULL
) free(asl
->facility
);
397 return (aslclient
)asl
;
400 __private_extern__
void
401 asl_client_release(asl_client_t
*asl
)
405 if (asl
== NULL
) return;
407 if(OSAtomicDecrement32(&asl
->refcount
) > 0)
413 if (asl
->sock
>= 0) close(asl
->sock
);
414 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_close();
415 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
417 if (asl
->fd_mfmt
!= NULL
)
419 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
423 if (asl
->fd_tfmt
!= NULL
)
425 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
429 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
431 memset(asl
, 0, sizeof(asl_client_t
));
436 asl_close(aslclient ac
)
438 asl_client_release((asl_client_t
*)ac
);
441 __private_extern__ asl_client_t
*
442 asl_client_retain(asl_client_t
*asl
)
446 if (asl
== NULL
) return NULL
;
448 new = OSAtomicIncrement32(&asl
->refcount
);
454 __private_extern__ asl_client_t
*
457 static dispatch_once_t once
;
459 dispatch_once(&once
, ^{
461 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
462 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
463 * which locks _asl_global.lock.
465 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
467 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
468 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
470 /* Now call _asl_notify_open(0) to finish the work */
474 return _asl_global
.asl
;
478 * asl_add_file: write log messages to the given file descriptor
479 * Log messages will be written to this file as well as to the server.
482 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
489 asl
= (asl_client_t
*)ac
;
492 asl
= _asl_open_default();
493 if (asl
== NULL
) return -1;
494 pthread_mutex_lock(&_asl_global
.lock
);
498 for (i
= 0; i
< asl
->fd_count
; i
++)
500 if (asl
->fd_list
[i
] == fd
)
502 /* update message format, time format, and text encoding */
503 if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
504 asl
->fd_mfmt
[i
] = NULL
;
505 if (mfmt
!= NULL
) asl
->fd_mfmt
[i
] = strdup(mfmt
);
507 if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
508 asl
->fd_tfmt
[i
] = NULL
;
509 if (tfmt
!= NULL
) asl
->fd_tfmt
[i
] = strdup(tfmt
);
511 asl
->fd_encoding
[i
] = text_encoding
;
513 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
518 if (asl
->fd_count
== 0)
520 asl
->fd_list
= (int *)calloc(1, sizeof(int));
521 asl
->fd_mfmt
= (char **)calloc(1, sizeof(char *));
522 asl
->fd_tfmt
= (char **)calloc(1, sizeof(char *));
523 asl
->fd_encoding
= (uint32_t *)calloc(1, sizeof(int));
527 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, (1 + asl
->fd_count
) * sizeof(int));
528 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, (1 + asl
->fd_count
) * sizeof(char *));
529 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, (1 + asl
->fd_count
) * sizeof(char *));
530 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, (1 + asl
->fd_count
) * sizeof(uint32_t));
533 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
535 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
536 if (asl
->fd_mfmt
!= NULL
) free(asl
->fd_mfmt
);
537 if (asl
->fd_tfmt
!= NULL
) free(asl
->fd_tfmt
);
538 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
540 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
544 asl
->fd_list
[asl
->fd_count
] = fd
;
545 if (mfmt
!= NULL
) asl
->fd_mfmt
[asl
->fd_count
] = strdup(mfmt
);
546 if (tfmt
!= NULL
) asl
->fd_tfmt
[asl
->fd_count
] = strdup(tfmt
);
547 asl
->fd_encoding
[asl
->fd_count
] = text_encoding
;
551 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
556 asl_add_log_file(aslclient ac
, int fd
)
558 return asl_add_output(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
562 * asl_remove_output: stop writing log messages to the given file descriptor
565 asl_remove_output(aslclient ac
, int fd
)
568 int x
, use_global_lock
;
572 asl
= (asl_client_t
*)ac
;
575 asl
= _asl_open_default();
576 if (asl
== NULL
) return -1;
577 pthread_mutex_lock(&_asl_global
.lock
);
581 if (asl
->fd_count
== 0)
583 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
588 for (i
= 0; i
< asl
->fd_count
; i
++)
590 if (asl
->fd_list
[i
] == fd
)
599 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
603 if (asl
->fd_mfmt
[x
] != NULL
) free(asl
->fd_mfmt
[x
]);
604 if (asl
->fd_tfmt
[x
] != NULL
) free(asl
->fd_tfmt
[x
]);
606 for (i
= x
+ 1; i
< asl
->fd_count
; i
++, x
++)
608 asl
->fd_list
[x
] = asl
->fd_list
[i
];
609 asl
->fd_mfmt
[x
] = asl
->fd_mfmt
[i
];
610 asl
->fd_tfmt
[x
] = asl
->fd_tfmt
[i
];
611 asl
->fd_encoding
[x
] = asl
->fd_encoding
[i
];
616 if (asl
->fd_count
== 0)
627 free(asl
->fd_encoding
);
628 asl
->fd_encoding
= NULL
;
632 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, asl
->fd_count
* sizeof(int));
633 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, asl
->fd_count
* sizeof(char *));
634 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, asl
->fd_count
* sizeof(char *));
635 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, asl
->fd_count
* sizeof(uint32_t));
637 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
639 if (asl
->fd_list
!= NULL
)
645 if (asl
->fd_mfmt
!= NULL
)
647 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
652 if (asl
->fd_tfmt
!= NULL
)
654 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
659 if (asl
->fd_encoding
!= NULL
)
661 free(asl
->fd_encoding
);
662 asl
->fd_encoding
= NULL
;
666 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
671 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
676 asl_remove_log_file(aslclient ac
, int fd
)
678 return asl_remove_output(ac
, fd
);
682 asl_set_filter(aslclient ac
, int f
)
684 int last
, use_global_lock
;
688 asl
= (asl_client_t
*)ac
;
691 asl
= _asl_open_default();
692 if (asl
== NULL
) return -1;
693 pthread_mutex_lock(&_asl_global
.lock
);
700 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
705 * Evaluate client / message / level to determine what to do with a message.
706 * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message
707 * can be ignored. Otherwise it returns the bits below, ORed with the level.
709 * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
710 * EVAL_SEND - will send to syslogd
711 * EVAL_TUNNEL - will send to syslogd with tunneling enabled
712 * EVAL_FILE - will write to file
715 _asl_evaluate_send(aslclient ac
, aslmsg msg
, int slevel
)
717 asl_client_t
*asl
= (asl_client_t
*)ac
;
718 uint32_t level
, lmask
, filter
, status
, tunnel
;
725 asl
= _asl_open_default();
726 if (asl
== NULL
) return EVAL_IGNORE
;
729 check
= ASL_LEVEL_DEBUG
;
730 if (slevel
>= 0) check
= slevel
;
732 val
= asl_get((aslmsg
)msg
, ASL_KEY_LEVEL
);
733 if (val
!= NULL
) check
= atoi(val
);
735 if (check
< ASL_LEVEL_EMERG
) check
= ASL_LEVEL_EMERG
;
736 else if (check
> ASL_LEVEL_DEBUG
) check
= ASL_LEVEL_DEBUG
;
741 if (asl
->aslfile
!= NULL
) return (out
| EVAL_ASLFILE
);
743 lmask
= ASL_FILTER_MASK(level
);
745 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
747 pthread_mutex_lock(&_asl_global
.lock
);
749 if (_asl_global
.rc_change_token
>= 0)
751 /* initialize or re-check process-specific and master filters */
753 status
= notify_check(_asl_global
.rc_change_token
, &check
);
754 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
756 if (_asl_global
.master_token
>= 0)
759 status
= notify_get_state(_asl_global
.master_token
, &v64
);
760 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
763 if (_asl_global
.notify_token
>= 0)
766 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
767 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
772 pthread_mutex_unlock(&_asl_global
.lock
);
775 filter
= asl
->filter
& 0xff;
776 tunnel
= (asl
->filter
& ASL_FILTER_MASK_TUNNEL
) >> 8;
778 /* master filter overrides local filter */
779 if (_asl_global
.master_filter
!= 0)
781 filter
= _asl_global
.master_filter
;
785 /* process-specific filter overrides local and master */
786 if (_asl_global
.proc_filter
!= 0)
788 filter
= _asl_global
.proc_filter
;
792 if ((filter
!= 0) && ((filter
& lmask
) != 0))
795 if (tunnel
!= 0) out
|= EVAL_TUNNEL
;
796 if (asl
->fd_count
> 0) out
|= EVAL_FILE
;
801 if ((asl
->options
& ASL_OPT_SYSLOG_LEGACY
) && (filter
!= 0) && ((filter
& lmask
) == 0))
806 if (asl
->fd_count
> 0) return (out
| EVAL_FILE
);
811 #endif /* BUILDING_VARIANT */
815 * Internal routine used by asl_vlog.
817 * eval: log level and send flags for the message
818 * format: A formating string
819 * ap: va_list for the format
820 * returns 0 for success, non-zero for failure
823 _asl_lib_vlog(aslclient ac
, uint32_t eval
, aslmsg msg
, const char *format
, va_list ap
)
825 int saved_errno
= errno
;
827 char *str
, *fmt
, estr
[NL_TEXTMAX
];
828 uint32_t i
, len
, elen
, expand
;
831 asl
= (asl_client_t
*)ac
;
835 * Initialize _asl_global so that asl_new will have global data.
836 * Not strictly necessary, but helps performance.
838 asl
= _asl_open_default();
839 if (asl
== NULL
) return -1;
842 if (format
== NULL
) return -1;
844 /* insert strerror for %m */
849 for (i
= 0; format
[i
] != '\0'; i
++)
851 if (format
[i
] == '%')
853 if (format
[i
+1] == '\0') len
++;
854 else if (format
[i
+1] == 'm')
857 strerror_r(saved_errno
, estr
, sizeof(estr
));
871 fmt
= (char *)format
;
875 fmt
= malloc(len
+ 1);
878 if (estr
!= NULL
) free(estr
);
884 for (i
= 0; format
[i
] != '\0'; i
++)
886 if (format
[i
] == '%')
888 if (format
[i
+1] == '\0')
891 else if ((format
[i
+1] == 'm') && (elen
!= 0))
893 memcpy(fmt
+len
, estr
, elen
);
899 fmt
[len
++] = format
[i
++];
900 fmt
[len
++] = format
[i
];
903 else fmt
[len
++] = format
[i
];
909 vasprintf(&str
, fmt
, ap
);
910 if (expand
!= 0) free(fmt
);
912 if (str
== NULL
) return -1;
914 status
= _asl_send_message(ac
, eval
, (asl_msg_t
*)msg
, str
);
922 * Similar to asl_log, but take a va_list instead of a list of arguments.
924 * level: the log level of the associated message
925 * format: A formating string
926 * ap: va_list for the format
927 * returns 0 for success, non-zero for failure
930 asl_vlog(aslclient ac
, aslmsg msg
, int level
, const char *format
, va_list ap
)
932 uint32_t eval
= _asl_evaluate_send(ac
, msg
, level
);
933 if (eval
== EVAL_IGNORE
) return 0;
935 return _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
940 * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
941 * forwards the call to _asl_lib_vlog.
943 * eval: log level and send flags for the message
944 * format: A formating string
945 * ... args for format
946 * returns 0 for success, non-zero for failure
949 _asl_lib_log(aslclient ac
, uint32_t eval
, aslmsg msg
, const char *format
, ...)
952 if (eval
== EVAL_IGNORE
) return 0;
955 va_start(ap
, format
);
956 status
= _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
964 * Processes an ASL log message.
966 * level: the log level of the associated message
967 * format: A formating string
968 * ... args for format
969 * returns 0 for success, non-zero for failure
972 asl_log(aslclient ac
, aslmsg msg
, int level
, const char *format
, ...)
975 uint32_t eval
= _asl_evaluate_send(ac
, msg
, level
);
976 if (eval
== EVAL_IGNORE
) return 0;
979 va_start(ap
, format
);
980 status
= _asl_lib_vlog(ac
, eval
, msg
, format
, ap
);
986 #ifndef BUILDING_VARIANT
989 * asl_get_filter: gets the values for the local, master, and remote filters,
990 * and indicates which one is active.
993 asl_get_filter(aslclient ac
, int *local
, int *master
, int *remote
, int *active
)
995 asl_client_t
*asl
, *asl_default
;
1005 asl_default
= _asl_open_default();
1007 asl
= (asl_client_t
*)ac
;
1008 if (asl
== NULL
) asl
= asl_default
;
1009 if (asl
!= NULL
) l
= asl
->filter
& 0xff;
1011 if ((asl_default
!= NULL
) && (!(asl_default
->options
& ASL_OPT_NO_REMOTE
)))
1013 pthread_mutex_lock(&_asl_global
.lock
);
1015 if (_asl_global
.rc_change_token
>= 0)
1017 /* initialize or re-check process-specific and master filters */
1019 status
= notify_check(_asl_global
.rc_change_token
, &check
);
1020 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
1022 if (_asl_global
.master_token
>= 0)
1025 status
= notify_get_state(_asl_global
.master_token
, &v64
);
1026 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
1029 if (_asl_global
.notify_token
>= 0)
1032 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
1033 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
1038 m
= _asl_global
.master_filter
;
1041 r
= _asl_global
.proc_filter
;
1044 pthread_mutex_unlock(&_asl_global
.lock
);
1047 if (local
!= NULL
) *local
= l
;
1048 if (master
!= NULL
) *master
= m
;
1049 if (remote
!= NULL
) *remote
= r
;
1050 if (active
!= NULL
) *active
= x
;
1056 _asl_send_message(aslclient ac
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
)
1058 uint32_t i
, len
, level
, lmask
, outstatus
, filter
, fd_write
;
1063 struct timeval tval
;
1066 int use_global_lock
;
1067 kern_return_t kstatus
;
1069 char aux_host
[_POSIX_HOST_NAME_MAX
];
1072 if (eval
== EVAL_IGNORE
) return 0;
1074 level
= eval
& LEVEL_MASK
;
1077 use_global_lock
= 0;
1078 asl
= (asl_client_t
*)ac
;
1081 asl
= _asl_open_default();
1082 if (asl
== NULL
) return -1;
1083 use_global_lock
= 1;
1086 if (asl
->aslfile
!= NULL
) use_global_lock
= 1;
1089 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here.
1090 * Also sets Sender & Facility (if unset) and "ASLOption store" if remote control is active.
1092 aux
= asl_msg_new(ASL_TYPE_MSG
);
1094 if (mstring
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstring
);
1096 snprintf(aux_val
, sizeof(aux_val
), "%u", level
);
1097 asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, aux_val
);
1099 memset(&tval
, 0, sizeof(struct timeval
));
1101 status
= gettimeofday(&tval
, NULL
);
1104 snprintf(aux_val
, sizeof(aux_val
), "%lu", tval
.tv_sec
);
1105 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
1106 snprintf(aux_val
, sizeof(aux_val
), "%d", tval
.tv_usec
* 1000);
1107 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
);
1112 snprintf(aux_val
, sizeof(aux_val
), "%lu", tick
);
1113 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
1116 memset(&aux_host
, 0, _POSIX_HOST_NAME_MAX
);
1117 if (gethostname(aux_host
, _POSIX_HOST_NAME_MAX
) == 0)
1119 asl_msg_set_key_val(aux
, ASL_KEY_HOST
, aux_host
);
1122 snprintf(aux_val
, sizeof(aux_val
), "%u", getpid());
1123 asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
);
1125 snprintf(aux_val
, sizeof(aux_val
), "%d", getuid());
1126 asl_msg_set_key_val(aux
, ASL_KEY_UID
, aux_val
);
1128 snprintf(aux_val
, sizeof(aux_val
), "%d", getgid());
1129 asl_msg_set_key_val(aux
, ASL_KEY_GID
, aux_val
);
1132 * Set Sender if needed
1134 status
= asl_msg_lookup((asl_msg_t
*)msg
, ASL_KEY_SENDER
, &val
, NULL
);
1135 if ((status
!= 0) || (val
== NULL
))
1137 if ((ac
!= NULL
) && (ac
->name
!= NULL
))
1139 /* Use the Sender name from the client handle */
1140 asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, ac
->name
);
1144 /* Get the value for ASL_KEY_SENDER from cache */
1145 if (_asl_global
.sender
== NULL
)
1147 name
= *(*_NSGetArgv());
1150 x
= strrchr(name
, '/');
1154 pthread_mutex_lock(&_asl_global
.lock
);
1155 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
1156 pthread_mutex_unlock(&_asl_global
.lock
);
1160 if (_asl_global
.sender
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
);
1161 else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown");
1168 status
= asl_msg_lookup((asl_msg_t
*)msg
, ASL_KEY_FACILITY
, &val
, NULL
);
1169 if ((status
!= 0) || (val
== NULL
))
1171 if ((ac
!= NULL
) && (ac
->facility
!= NULL
))
1173 /* Use the Facility name from the client handle */
1174 asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, ac
->facility
);
1178 /* Set "ASLOption store" if tunneling */
1180 if (eval
& EVAL_TUNNEL
)
1182 val
= asl_get((aslmsg
)msg
, ASL_KEY_OPTION
);
1185 asl_msg_set_key_val(aux
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
1189 char *aux_option
= NULL
;
1190 asprintf(&aux_option
, "%s %s", ASL_OPT_STORE
, val
);
1191 asl_msg_set_key_val(aux
, ASL_KEY_OPTION
, aux_option
);
1198 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
1200 aux
= asl_msg_merge(aux
, msg
);
1203 * If there is an aslfile this is a stand-alone file client.
1204 * Just save to the file.
1206 if (asl
->aslfile
!= NULL
)
1208 outstatus
= ASL_STATUS_FAILED
;
1212 outstatus
= asl_file_save(asl
->aslfile
, (aslmsg
)aux
, &(asl
->aslfileid
));
1216 asl_msg_release(aux
);
1218 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1225 if ((_asl_global
.server_port
!= MACH_PORT_NULL
) && (eval
& EVAL_SEND
))
1227 asl_string_t
*send_str
;
1231 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, 0);
1232 len
= asl_string_length(send_str
);
1233 vmsize
= asl_string_allocated_size(send_str
);
1234 str
= asl_string_free_return_bytes(send_str
);
1238 /* send a mach message to syslogd */
1239 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1240 if (kstatus
!= KERN_SUCCESS
)
1242 /* retry once if the call failed */
1243 _asl_global_reset();
1245 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1246 if (kstatus
!= KERN_SUCCESS
)
1248 _asl_global_reset();
1249 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1256 /* messages from syslog() get filtered on the way out to stderr */
1258 if ((asl
->options
& ASL_OPT_SYSLOG_LEGACY
) && (filter
!= 0) && ((filter
& lmask
) == 0)) fd_write
= 0;
1260 if ((fd_write
!= 0) && (asl
->fd_count
> 0))
1264 /* write to file descriptors */
1266 for (i
= 0; i
< asl
->fd_count
; i
++)
1270 if (asl
->fd_list
[i
] < 0) continue;
1273 str
= asl_format_message(aux
, asl
->fd_mfmt
[i
], asl
->fd_tfmt
[i
], asl
->fd_encoding
[i
], &len
);
1274 if (str
== NULL
) continue;
1276 status
= write(asl
->fd_list
[i
], str
, len
- 1);
1279 asl
->fd_list
[i
] = -1;
1288 asl_msg_release(aux
);
1290 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1296 * asl_send: send a message
1297 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1298 * has been used to set all of a message's attributes.
1299 * eval: hints about what to do with the message
1301 * returns 0 for success, non-zero for failure
1304 asl_send(aslclient ac
, aslmsg msg
)
1307 uint32_t eval
= _asl_evaluate_send(ac
, msg
, -1);
1308 if (eval
!= 0) status
= _asl_send_message(ac
, eval
, (asl_msg_t
*)msg
, NULL
);
1314 _asl_aux_save_context(asl_aux_context_t
*ctx
)
1316 if (ctx
== NULL
) return -1;
1318 pthread_mutex_lock(&_asl_global
.lock
);
1320 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count
+ 1) * sizeof(asl_aux_context_t
*));
1321 if (_asl_global
.aux_ctx
== NULL
)
1323 _asl_global
.aux_count
= 0;
1327 _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
;
1329 pthread_mutex_unlock(&_asl_global
.lock
);
1335 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1336 * will be saved at the time that the auxiliary file is created. The message will include
1337 * any keys and values found in msg, and it will include the title and Uniform Type
1338 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1339 * new auxiliary file.
1342 _asl_auxiliary(asl_msg_t
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
)
1345 asl_string_t
*send_str
;
1347 fileport_t fileport
;
1348 kern_return_t kstatus
;
1350 uint32_t newurllen
, where
;
1351 int status
, fd
, fdpair
[2];
1353 dispatch_queue_t pipe_q
;
1354 dispatch_io_t pipe_channel
;
1355 dispatch_semaphore_t sem
;
1357 aux
= asl_msg_new(ASL_TYPE_MSG
);
1361 asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
);
1366 asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data");
1370 asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
);
1375 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
);
1378 aux
= asl_msg_merge(aux
, msg
);
1380 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1383 uint32_t eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux
, -1);
1384 status
= _asl_send_message(NULL
, eval
, aux
, NULL
);
1385 asl_msg_release(aux
);
1389 where
= asl_store_location();
1391 if (where
== ASL_STORE_LOCATION_MEMORY
)
1395 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1396 if (ctx
== NULL
) return -1;
1398 status
= pipe(fdpair
);
1405 /* give read end to dispatch_io_read */
1407 sem
= dispatch_semaphore_create(0);
1409 ctx
->fd
= fdpair
[1];
1411 status
= _asl_aux_save_context(ctx
);
1416 dispatch_release(sem
);
1421 pipe_q
= dispatch_queue_create("PipeQ", NULL
);
1422 pipe_channel
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){
1426 *out_fd
= fdpair
[1];
1428 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
);
1430 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){
1433 size_t len
= dispatch_data_get_size(pipedata
);
1436 const char *bytes
= NULL
;
1440 dispatch_data_t md
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
);
1441 encoded
= asl_core_encode_buffer(bytes
, len
);
1442 asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
);
1444 eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux
, -1);
1445 _asl_send_message(NULL
, eval
, aux
, NULL
);
1446 asl_msg_release(aux
);
1447 dispatch_release(md
);
1453 dispatch_semaphore_signal(sem
);
1454 dispatch_release(pipe_channel
);
1455 dispatch_release(pipe_q
);
1463 if (_asl_global
.server_port
== MACH_PORT_NULL
) return -1;
1465 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, 0);
1466 len
= asl_string_length(send_str
);
1467 vmsize
= asl_string_allocated_size(send_str
);
1468 str
= asl_string_free_return_bytes(send_str
);
1472 asl_msg_release(aux
);
1473 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1478 fileport
= MACH_PORT_NULL
;
1479 status
= KERN_SUCCESS
;
1481 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1482 if (kstatus
!= KERN_SUCCESS
)
1484 /* retry once if the call failed */
1485 _asl_global_reset();
1487 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1488 if (kstatus
!= KERN_SUCCESS
)
1490 _asl_global_reset();
1491 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1492 asl_msg_release(aux
);
1499 asl_msg_release(aux
);
1505 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
);
1506 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
);
1509 if (fileport
== MACH_PORT_NULL
)
1511 asl_msg_release(aux
);
1515 fd
= fileport_makefd(fileport
);
1516 mach_port_deallocate(mach_task_self(), fileport
);
1519 asl_msg_release(aux
);
1524 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1536 status
= _asl_aux_save_context(ctx
);
1544 asl_create_auxiliary_file(aslmsg msg
, const char *title
, const char *uti
, int *out_fd
)
1546 if (out_fd
== NULL
) return -1;
1548 return _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, NULL
, out_fd
);
1552 asl_log_auxiliary_location(aslmsg msg
, const char *title
, const char *uti
, const char *url
)
1554 return _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, url
, NULL
);
1558 * Close an auxiliary file.
1559 * Sends the cached auxiliary message to syslogd.
1562 asl_close_auxiliary_file(int fd
)
1566 dispatch_semaphore_t aux_sem
;
1568 pthread_mutex_lock(&(_asl_global
.lock
));
1573 for (i
= 0; i
< _asl_global
.aux_count
; i
++)
1575 if (_asl_global
.aux_ctx
[i
]->fd
== fd
)
1579 aux_msg
= _asl_global
.aux_ctx
[i
]->msg
;
1580 aux_sem
= _asl_global
.aux_ctx
[i
]->sem
;
1582 free(_asl_global
.aux_ctx
[i
]);
1584 for (j
= i
+ 1; j
< _asl_global
.aux_count
; i
++, j
++)
1586 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
];
1589 _asl_global
.aux_count
--;
1591 if (_asl_global
.aux_count
== 0)
1593 free(_asl_global
.aux_ctx
);
1594 _asl_global
.aux_ctx
= NULL
;
1598 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count
* sizeof(asl_aux_context_t
*));
1599 if (_asl_global
.aux_ctx
== NULL
)
1601 _asl_global
.aux_count
= 0;
1610 pthread_mutex_unlock(&(_asl_global
.lock
));
1614 if (aux_msg
!= NULL
)
1616 uint32_t eval
= _asl_evaluate_send(NULL
, (aslmsg
)aux_msg
, -1);
1617 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status
= -1;
1618 asl_msg_release(aux_msg
);
1621 if (aux_sem
!= NULL
)
1623 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
);
1624 dispatch_release(aux_sem
);
1631 * asl_search: Search for messages matching the criteria described
1632 * by the aslmsg. The caller should set the attributes to match using
1633 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
1634 * used for attributes set with asl_set().
1636 * returns: a set of messages that can be iterated over using aslresp_next(),
1637 * and the values can be retrieved using aslresp_get.
1641 * This routine searches the ASL datastore on disk (/var/log/asl).
1642 * It is called my asl_search if syslogd is not running or if syslogd
1643 * indicates that an in-memory store is not being used.
1646 _asl_search_store(aslclient ac
, aslmsg a
)
1648 asl_search_result_t query
, *out
;
1649 asl_msg_t
*q
, *qlist
[1];
1650 uint32_t status
, op
;
1651 uint64_t last_id
, start_id
;
1655 if (a
== NULL
) return NULL
;
1659 /* check for "ASLMessageId >[=] n" and set start_id */
1663 status
= asl_msg_lookup(q
, ASL_KEY_MSG_ID
, &val
, &op
);
1664 if ((status
== 0) && (val
!= NULL
) && (op
& ASL_QUERY_OP_GREATER
))
1666 if (op
& ASL_QUERY_OP_EQUAL
) start_id
= atoll(val
);
1667 else start_id
= atoll(val
) + 1;
1671 status
= asl_store_open_read(NULL
, &store
);
1672 if (status
!= 0) return NULL
;
1673 if (store
== NULL
) return NULL
;
1678 qlist
[0] = (asl_msg_t
*)a
;
1679 memset(&query
, 0, sizeof(asl_search_result_t
));
1683 status
= asl_store_match(store
, &query
, &out
, &last_id
, start_id
, 0, 1);
1684 asl_store_close(store
);
1690 _asl_search_concat_results(asl_search_result_t
*batch
, asl_search_result_t
**out
)
1694 if (out
== NULL
) return ASL_STATUS_FAILED
;
1696 /* nothing to do if batch is NULL or contains no messages */
1697 if (batch
== NULL
) return 0;
1698 if (batch
->count
== 0)
1700 aslresponse_free(batch
);
1704 if (*out
== NULL
) *out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1707 aslresponse_free(batch
);
1708 return ASL_STATUS_FAILED
;
1711 if ((*out
)->count
== 0)
1713 (*out
)->msg
= (asl_msg_t
**)calloc(batch
->count
, sizeof(asl_msg_t
*));
1717 (*out
)->msg
= (asl_msg_t
**)reallocf((*out
)->msg
, ((*out
)->count
+ batch
->count
) * sizeof(asl_msg_t
*));
1720 if ((*out
)->msg
== NULL
)
1722 aslresponse_free(batch
);
1725 return ASL_STATUS_FAILED
;
1728 for (i
= 0, j
= (*out
)->count
; i
< batch
->count
; i
++, j
++) (*out
)->msg
[j
] = batch
->msg
[i
];
1730 (*out
)->count
+= batch
->count
;
1733 return ASL_STATUS_OK
;
1737 _asl_search_memory(aslclient ac
, aslmsg a
)
1739 asl_search_result_t
*batch
, *out
;
1740 char *qstr
, *str
, *res
;
1741 uint32_t len
, reslen
, status
;
1742 uint64_t cmax
, qmin
;
1743 kern_return_t kstatus
;
1744 security_token_t sec
;
1747 if (a
== NULL
) return 0;
1750 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1753 qstr
= asl_msg_to_string((asl_msg_t
*)a
, &len
);
1758 asprintf(&str
, "0\n");
1763 asprintf(&str
, "1\n%s\n", qstr
);
1768 if (str
== NULL
) return NULL
;
1771 * Fetch a batch of results each time through the loop.
1772 * Fetching small batches rebuces the load on syslogd.
1784 status
= ASL_STATUS_OK
;
1786 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
1787 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1789 memmove(vmstr
, str
, len
);
1792 kstatus
= _asl_server_query(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1793 if (kstatus
!= KERN_SUCCESS
)
1795 /* retry once if the call failed */
1796 _asl_global_reset();
1798 kstatus
= _asl_server_query(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1799 if (kstatus
!= KERN_SUCCESS
)
1801 _asl_global_reset();
1806 if (res
== NULL
) break;
1808 batch
= asl_list_from_string(res
);
1809 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1811 status
= _asl_search_concat_results(batch
, &out
);
1812 if (status
!= ASL_STATUS_OK
) break;
1813 if ((out
== NULL
) || (out
->count
< FETCH_BATCH
)) break;
1815 if (cmax
>= qmin
) qmin
= cmax
+ 1;
1824 asl_store_location()
1826 kern_return_t kstatus
;
1828 uint32_t reslen
, status
;
1830 security_token_t sec
;
1833 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
1840 status
= ASL_STATUS_OK
;
1842 kstatus
= _asl_server_query(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1843 if (kstatus
!= KERN_SUCCESS
)
1845 /* retry once if the call failed */
1846 _asl_global_reset();
1848 kstatus
= _asl_server_query(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1851 /* res should never be returned, but just to be certain we don't leak VM ... */
1852 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1854 if (kstatus
!= KERN_SUCCESS
)
1856 _asl_global_reset();
1857 return ASL_STORE_LOCATION_FILE
;
1860 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
1861 return ASL_STORE_LOCATION_FILE
;
1865 asl_search(aslclient ac
, aslmsg a
)
1868 asl_search_result_t
*out
;
1872 where
= asl_store_location();
1873 if (where
== ASL_STORE_LOCATION_FILE
) out
= _asl_search_store(ac
, a
);
1874 else out
= _asl_search_memory(ac
, a
);
1880 asl_syslog_faciliy_name_to_num(const char *name
)
1882 if (name
== NULL
) return -1;
1884 if (strcaseeq(name
, "auth")) return LOG_AUTH
;
1885 if (strcaseeq(name
, "authpriv")) return LOG_AUTHPRIV
;
1886 if (strcaseeq(name
, "cron")) return LOG_CRON
;
1887 if (strcaseeq(name
, "daemon")) return LOG_DAEMON
;
1888 if (strcaseeq(name
, "ftp")) return LOG_FTP
;
1889 if (strcaseeq(name
, "install")) return LOG_INSTALL
;
1890 if (strcaseeq(name
, "kern")) return LOG_KERN
;
1891 if (strcaseeq(name
, "lpr")) return LOG_LPR
;
1892 if (strcaseeq(name
, "mail")) return LOG_MAIL
;
1893 if (strcaseeq(name
, "netinfo")) return LOG_NETINFO
;
1894 if (strcaseeq(name
, "remoteauth")) return LOG_REMOTEAUTH
;
1895 if (strcaseeq(name
, "news")) return LOG_NEWS
;
1896 if (strcaseeq(name
, "security")) return LOG_AUTH
;
1897 if (strcaseeq(name
, "syslog")) return LOG_SYSLOG
;
1898 if (strcaseeq(name
, "user")) return LOG_USER
;
1899 if (strcaseeq(name
, "uucp")) return LOG_UUCP
;
1900 if (strcaseeq(name
, "local0")) return LOG_LOCAL0
;
1901 if (strcaseeq(name
, "local1")) return LOG_LOCAL1
;
1902 if (strcaseeq(name
, "local2")) return LOG_LOCAL2
;
1903 if (strcaseeq(name
, "local3")) return LOG_LOCAL3
;
1904 if (strcaseeq(name
, "local4")) return LOG_LOCAL4
;
1905 if (strcaseeq(name
, "local5")) return LOG_LOCAL5
;
1906 if (strcaseeq(name
, "local6")) return LOG_LOCAL6
;
1907 if (strcaseeq(name
, "local7")) return LOG_LOCAL7
;
1908 if (strcaseeq(name
, "launchd")) return LOG_LAUNCHD
;
1914 asl_syslog_faciliy_num_to_name(int n
)
1916 if (n
< 0) return NULL
;
1918 if (n
== LOG_AUTH
) return "auth";
1919 if (n
== LOG_AUTHPRIV
) return "authpriv";
1920 if (n
== LOG_CRON
) return "cron";
1921 if (n
== LOG_DAEMON
) return "daemon";
1922 if (n
== LOG_FTP
) return "ftp";
1923 if (n
== LOG_INSTALL
) return "install";
1924 if (n
== LOG_KERN
) return "kern";
1925 if (n
== LOG_LPR
) return "lpr";
1926 if (n
== LOG_MAIL
) return "mail";
1927 if (n
== LOG_NETINFO
) return "netinfo";
1928 if (n
== LOG_REMOTEAUTH
) return "remoteauth";
1929 if (n
== LOG_NEWS
) return "news";
1930 if (n
== LOG_AUTH
) return "security";
1931 if (n
== LOG_SYSLOG
) return "syslog";
1932 if (n
== LOG_USER
) return "user";
1933 if (n
== LOG_UUCP
) return "uucp";
1934 if (n
== LOG_LOCAL0
) return "local0";
1935 if (n
== LOG_LOCAL1
) return "local1";
1936 if (n
== LOG_LOCAL2
) return "local2";
1937 if (n
== LOG_LOCAL3
) return "local3";
1938 if (n
== LOG_LOCAL4
) return "local4";
1939 if (n
== LOG_LOCAL5
) return "local5";
1940 if (n
== LOG_LOCAL6
) return "local6";
1941 if (n
== LOG_LOCAL7
) return "local7";
1942 if (n
== LOG_LAUNCHD
) return "launchd";
1948 * utility for converting a time string into a time_t
1949 * we only deal with the following formats:
1950 * Canonical form YYYY.MM.DD hh:mm:ss UTC
1951 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
1952 * absolute form - # seconds since the epoch (e.g. 1095789191)
1953 * relative time - seconds before or after now (e.g. -300, +43200)
1954 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
1957 #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$"
1958 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
1959 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
1960 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
1962 #define SECONDS_PER_MINUTE 60
1963 #define SECONDS_PER_HOUR 3600
1964 #define SECONDS_PER_DAY 86400
1965 #define SECONDS_PER_WEEK 604800
1967 static regex_t rex_canon
, rex_ctime
, rex_abs
, rex_rel
;
1968 static int reg_status
= 0;
1971 * We use the last letter in the month name to determine
1972 * the month number (0-11). There are two collisions:
1973 * Jan and Jun both end in n
1974 * Mar and Apr both end in r
1975 * In these cases we check the second letter.
1977 * The MTH_LAST array maps the last letter to a number.
1979 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};
1988 if (s
[2] > 90) v8
= s
[2] - 'a';
1989 else v8
= s
[2] - 'A';
1991 if ((v8
< 0) || (v8
> 25)) return -1;
1994 if (v8
< 0) return -1;
1997 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
1998 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
2003 asl_parse_time(const char *in
)
2007 time_t tick
, delta
, factor
;
2009 static dispatch_once_t once
;
2011 if (in
== NULL
) return -1;
2013 dispatch_once(&once
, ^{
2015 int rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
2017 memset(&rex_canon
, 0, sizeof(regex_t
));
2018 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
2019 if (status
!= 0) reg_status
= -1;
2021 memset(&rex_ctime
, 0, sizeof(regex_t
));
2022 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
2023 if (status
!= 0) reg_status
= -1;
2025 memset(&rex_abs
, 0, sizeof(regex_t
));
2026 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
2027 if (status
!= 0) reg_status
= -1;
2029 memset(&rex_rel
, 0, sizeof(regex_t
));
2030 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
2031 if (status
!= 0) reg_status
= -1;
2034 if (reg_status
< 0) return -1;
2036 len
= strlen(in
) + 1;
2038 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
2041 * Absolute time (number of seconds since the epoch)
2044 if (str
== NULL
) return -1;
2046 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
2053 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
2056 * Reletive time (number of seconds before or after right now)
2059 if (str
== NULL
) return -1;
2063 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
2067 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
2070 factor
= SECONDS_PER_MINUTE
;
2072 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
2075 factor
= SECONDS_PER_HOUR
;
2077 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
2080 factor
= SECONDS_PER_DAY
;
2082 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
2085 factor
= SECONDS_PER_WEEK
;
2089 delta
= factor
* atol(str
);
2096 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
2098 memset(&t
, 0, sizeof(struct tm
));
2100 if (str
== NULL
) return -1;
2106 t
.tm_year
= atoi(x
) - 1900;
2112 t
.tm_mon
= atoi(x
) - 1;
2118 t
.tm_mday
= atoi(x
);
2121 for (x
= p
+ 1; *x
== ' '; x
++);
2124 t
.tm_hour
= atoi(x
);
2141 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
2143 /* We assume it's in the current year */
2144 memset(&t
, 0, sizeof(struct tm
));
2146 gmtime_r(&tick
, &t
);
2149 memset(&t
, 0, sizeof(struct tm
));
2151 if (str
== NULL
) return -1;
2154 t
.tm_mon
= _month_num(str
);
2155 if (t
.tm_mon
< 0) return -1;
2157 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
2160 t
.tm_mday
= atoi(x
);
2163 for (x
= p
+ 1; *x
== ' '; x
++);
2166 t
.tm_hour
= atoi(x
);
2187 #endif /* BUILDING_VARIANT */