2 * Copyright (c) 2004-2010 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@
36 #include <sys/fcntl.h>
37 #include <crt_externs.h>
41 #include <mach/mach.h>
42 #include <mach/std_types.h>
44 #include <mach/mach_types.h>
45 #include <sys/types.h>
46 #include <servers/bootstrap.h>
48 #include <dispatch/dispatch.h>
52 #include "asl_store.h"
53 #include "asl_private.h"
55 #define streq(A, B) (strcmp(A, B) == 0)
56 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
58 #define forever for(;;)
60 #define FETCH_BATCH 256
63 time_t asl_parse_time(const char *);
64 const char *asl_syslog_faciliy_num_to_name(int n
);
65 __private_extern__
int _asl_send_message(aslclient ac
, asl_msg_t
*msg
, int slevel
, const char *aux_message
);
66 __private_extern__ asl_client_t
*_asl_open_default();
68 /* private asl_msg SPI */
69 __private_extern__
uint32_t _asl_msg_string_length_aux(asl_msg_t
*msg
, asl_msg_aux_t
*aux
);
70 __private_extern__
uint32_t _asl_msg_to_string_buffer_aux(asl_msg_t
*msg
, asl_msg_aux_t
*aux
, char *buf
, uint32_t bufsize
);
72 /* private asl_file SPI */
73 __private_extern__
uint32_t asl_file_open_write_fd(int fd
, asl_file_t
**s
);
76 uint32_t notify_register_plain(const char *name
, int *out_token
);
78 /* fork handling in syslog.c */
79 extern void _syslog_fork_child();
85 dispatch_semaphore_t sem
;
95 uint64_t master_filter
;
96 dispatch_once_t port_lookup_once
;
97 mach_port_t server_port
;
101 asl_aux_context_t
**aux_ctx
;
106 #ifndef BUILDING_VARIANT
107 __private_extern__ _asl_global_t _asl_global
= {0, -1, -1, -1, 0LL, 0LL, 0, MACH_PORT_NULL
, NULL
, PTHREAD_MUTEX_INITIALIZER
, 0, NULL
, NULL
};
109 #define ASL_SERVICE_NAME "com.apple.system.logger"
112 * Called from the child process inside fork() to clean up
113 * inherited state from the parent process.
115 * NB. A lock isn't required, since we're single threaded in this call.
117 __private_extern__
void
120 _asl_global
.notify_count
= 0;
121 _asl_global
.rc_change_token
= -1;
122 _asl_global
.master_token
= -1;
123 _asl_global
.notify_token
= -1;
125 _asl_global
.port_lookup_once
= 0;
126 _asl_global
.server_port
= MACH_PORT_NULL
;
130 * asl_remote_notify_name: returns the notification key for remote-control filter
131 * changes for this process.
134 asl_remote_notify_name()
136 pid_t pid
= getpid();
137 uid_t euid
= geteuid();
140 if (euid
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
);
141 else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
);
147 _asl_notify_open(int do_lock
)
152 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
154 _asl_global
.notify_count
++;
156 if (_asl_global
.notify_token
!= -1)
158 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
162 if (_asl_global
.rc_change_token
== -1)
164 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
165 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
168 if (_asl_global
.master_token
== -1)
170 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
171 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
174 notify_name
= asl_remote_notify_name();
175 if (notify_name
!= NULL
)
177 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
179 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
182 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
184 if (_asl_global
.notify_token
== -1) return -1;
191 pthread_mutex_lock(&_asl_global
.lock
);
193 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
195 if (_asl_global
.notify_count
> 0)
197 pthread_mutex_unlock(&_asl_global
.lock
);
201 if (_asl_global
.rc_change_token
>= 0) notify_cancel(_asl_global
.rc_change_token
);
202 _asl_global
.rc_change_token
= -1;
204 if (_asl_global
.master_token
>= 0) notify_cancel(_asl_global
.master_token
);
205 _asl_global
.master_token
= -1;
207 if (_asl_global
.notify_token
>= 0) notify_cancel(_asl_global
.notify_token
);
208 _asl_global
.notify_token
= -1;
210 pthread_mutex_unlock(&_asl_global
.lock
);
216 dispatch_once(&_asl_global
.port_lookup_once
, ^{
217 char *str
= getenv("ASL_DISABLE");
218 if ((str
== NULL
) || strcmp(str
, "1"))
220 bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &_asl_global
.server_port
);
226 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
231 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
248 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
252 asl
->name
= strdup(ident
);
253 if (asl
->name
== NULL
)
255 if (asl
->sock
>= 0) close(asl
->sock
);
262 name
= *(*_NSGetArgv());
265 x
= strrchr(name
, '/');
268 asl
->name
= strdup(x
);
269 if (asl
->name
== NULL
)
271 if (asl
->sock
>= 0) close(asl
->sock
);
278 asl
->facility
= NULL
;
279 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
280 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
281 if (asl
->facility
== NULL
)
283 if (asl
->sock
>= 0) close(asl
->sock
);
284 if (asl
->name
!= NULL
) free(asl
->name
);
289 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
291 if (asl
->options
& ASL_OPT_STDERR
) asl_add_output((aslclient
)asl
, fileno(stderr
), ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
293 return (aslclient
)asl
;
297 asl_open_from_file(int fd
, const char *ident
, const char *facility
)
303 asl
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
310 asl
->options
= ASL_OPT_NO_REMOTE
;
317 asl
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
);
321 asl
->name
= strdup(ident
);
322 if (asl
->name
== NULL
)
330 name
= *(*_NSGetArgv());
333 x
= strrchr(name
, '/');
336 asl
->name
= strdup(x
);
337 if (asl
->name
== NULL
)
345 asl
->facility
= NULL
;
346 if (facility
!= NULL
) asl
->facility
= strdup(facility
);
347 else asl
->facility
= strdup(asl_syslog_faciliy_num_to_name(LOG_USER
));
348 if (asl
->facility
== NULL
)
350 if (asl
->name
!= NULL
) free(asl
->name
);
355 status
= asl_file_open_write_fd(fd
, &(asl
->aslfile
));
356 if (status
!= ASL_STATUS_OK
)
358 if (asl
->name
!= NULL
) free(asl
->name
);
359 if (asl
->facility
!= NULL
) free(asl
->facility
);
366 return (aslclient
)asl
;
370 asl_close(aslclient ac
)
375 asl
= (asl_client_t
*)ac
;
376 if (asl
== NULL
) return;
381 if (asl
->sock
>= 0) close(asl
->sock
);
382 if (!(asl
->options
& ASL_OPT_NO_REMOTE
)) _asl_notify_close();
383 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
385 if (asl
->fd_mfmt
!= NULL
)
387 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
391 if (asl
->fd_tfmt
!= NULL
)
393 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
397 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
399 memset(asl
, 0, sizeof(asl_client_t
));
403 __private_extern__ asl_client_t
*
406 static dispatch_once_t once
;
408 dispatch_once(&once
, ^{
410 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
411 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
412 * which locks _asl_global.lock.
414 _asl_global
.asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
416 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
417 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
419 /* Now call _asl_notify_open(0) to finish the work */
423 return _asl_global
.asl
;
427 * asl_add_file: write log messages to the given file descriptor
428 * Log messages will be written to this file as well as to the server.
431 asl_add_output(aslclient ac
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
438 asl
= (asl_client_t
*)ac
;
441 asl
= _asl_open_default();
442 if (asl
== NULL
) return -1;
443 pthread_mutex_lock(&_asl_global
.lock
);
447 for (i
= 0; i
< asl
->fd_count
; i
++)
449 if (asl
->fd_list
[i
] == fd
)
451 /* update message format, time format, and text encoding */
452 if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
453 asl
->fd_mfmt
[i
] = NULL
;
454 if (mfmt
!= NULL
) asl
->fd_mfmt
[i
] = strdup(mfmt
);
456 if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
457 asl
->fd_tfmt
[i
] = NULL
;
458 if (tfmt
!= NULL
) asl
->fd_tfmt
[i
] = strdup(tfmt
);
460 asl
->fd_encoding
[i
] = text_encoding
;
462 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
467 if (asl
->fd_count
== 0)
469 asl
->fd_list
= (int *)calloc(1, sizeof(int));
470 asl
->fd_mfmt
= (char **)calloc(1, sizeof(char *));
471 asl
->fd_tfmt
= (char **)calloc(1, sizeof(char *));
472 asl
->fd_encoding
= (uint32_t *)calloc(1, sizeof(int));
476 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, (1 + asl
->fd_count
) * sizeof(int));
477 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, (1 + asl
->fd_count
) * sizeof(char *));
478 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, (1 + asl
->fd_count
) * sizeof(char *));
479 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, (1 + asl
->fd_count
) * sizeof(uint32_t));
482 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
484 if (asl
->fd_list
!= NULL
) free(asl
->fd_list
);
485 if (asl
->fd_mfmt
!= NULL
) free(asl
->fd_mfmt
);
486 if (asl
->fd_tfmt
!= NULL
) free(asl
->fd_tfmt
);
487 if (asl
->fd_encoding
!= NULL
) free(asl
->fd_encoding
);
489 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
493 asl
->fd_list
[asl
->fd_count
] = fd
;
494 if (mfmt
!= NULL
) asl
->fd_mfmt
[asl
->fd_count
] = strdup(mfmt
);
495 if (tfmt
!= NULL
) asl
->fd_tfmt
[asl
->fd_count
] = strdup(tfmt
);
496 asl
->fd_encoding
[asl
->fd_count
] = text_encoding
;
500 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
505 asl_add_log_file(aslclient ac
, int fd
)
507 return asl_add_output(ac
, fd
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
);
511 * asl_remove_output: stop writing log messages to the given file descriptor
514 asl_remove_output(aslclient ac
, int fd
)
517 int x
, use_global_lock
;
521 asl
= (asl_client_t
*)ac
;
524 asl
= _asl_open_default();
525 if (asl
== NULL
) return -1;
526 pthread_mutex_lock(&_asl_global
.lock
);
530 if (asl
->fd_count
== 0)
532 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
537 for (i
= 0; i
< asl
->fd_count
; i
++)
539 if (asl
->fd_list
[i
] == fd
)
548 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
552 if (asl
->fd_mfmt
[x
] != NULL
) free(asl
->fd_mfmt
[x
]);
553 if (asl
->fd_tfmt
[x
] != NULL
) free(asl
->fd_tfmt
[x
]);
555 for (i
= x
+ 1; i
< asl
->fd_count
; i
++, x
++)
557 asl
->fd_list
[x
] = asl
->fd_list
[i
];
558 asl
->fd_mfmt
[x
] = asl
->fd_mfmt
[i
];
559 asl
->fd_tfmt
[x
] = asl
->fd_tfmt
[i
];
560 asl
->fd_encoding
[x
] = asl
->fd_encoding
[i
];
565 if (asl
->fd_count
== 0)
576 free(asl
->fd_encoding
);
577 asl
->fd_encoding
= NULL
;
581 asl
->fd_list
= (int *)reallocf(asl
->fd_list
, asl
->fd_count
* sizeof(int));
582 asl
->fd_mfmt
= (char **)reallocf(asl
->fd_mfmt
, asl
->fd_count
* sizeof(char *));
583 asl
->fd_tfmt
= (char **)reallocf(asl
->fd_tfmt
, asl
->fd_count
* sizeof(char *));
584 asl
->fd_encoding
= (uint32_t *)reallocf(asl
->fd_encoding
, asl
->fd_count
* sizeof(uint32_t));
586 if ((asl
->fd_list
== NULL
) || (asl
->fd_mfmt
== NULL
) || (asl
->fd_tfmt
== NULL
) || (asl
->fd_encoding
== NULL
))
588 if (asl
->fd_list
!= NULL
)
594 if (asl
->fd_mfmt
!= NULL
)
596 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_mfmt
[i
] != NULL
) free(asl
->fd_mfmt
[i
]);
601 if (asl
->fd_tfmt
!= NULL
)
603 for (i
= 0; i
< asl
->fd_count
; i
++) if (asl
->fd_tfmt
[i
] != NULL
) free(asl
->fd_tfmt
[i
]);
608 if (asl
->fd_encoding
!= NULL
)
610 free(asl
->fd_encoding
);
611 asl
->fd_encoding
= NULL
;
615 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
620 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
625 asl_remove_log_file(aslclient ac
, int fd
)
627 return asl_remove_output(ac
, fd
);
631 asl_set_filter(aslclient ac
, int f
)
633 int last
, use_global_lock
;
637 asl
= (asl_client_t
*)ac
;
640 asl
= _asl_open_default();
641 if (asl
== NULL
) return -1;
642 pthread_mutex_lock(&_asl_global
.lock
);
649 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
653 #endif /* BUILDING_VARIANT */
656 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
659 * level: the log level of the associated message
660 * format: A formating string followed by a list of arguments, like vprintf()
661 * returns 0 for success, non-zero for failure
664 asl_vlog(aslclient ac
, aslmsg msg
, int level
, const char *format
, va_list ap
)
666 int saved_errno
= errno
;
668 char *str
, *fmt
, estr
[NL_TEXTMAX
];
669 uint32_t i
, len
, elen
, expand
;
672 asl
= (asl_client_t
*)ac
;
676 * Initialize _asl_global so that asl_new will have global data.
677 * Not strictly necessary, but helps performance.
679 asl
= _asl_open_default();
680 if (asl
== NULL
) return -1;
683 if (format
== NULL
) return -1;
685 /* insert strerror for %m */
690 for (i
= 0; format
[i
] != '\0'; i
++)
692 if (format
[i
] == '%')
694 if (format
[i
+1] == '\0') len
++;
695 else if (format
[i
+1] == 'm')
698 strerror_r(saved_errno
, estr
, sizeof(estr
));
712 fmt
= (char *)format
;
716 fmt
= malloc(len
+ 1);
719 if (estr
!= NULL
) free(estr
);
725 for (i
= 0; format
[i
] != '\0'; i
++)
727 if (format
[i
] == '%')
729 if (format
[i
+1] == '\0')
732 else if ((format
[i
+1] == 'm') && (elen
!= 0))
734 memcpy(fmt
+len
, estr
, elen
);
740 fmt
[len
++] = format
[i
++];
741 fmt
[len
++] = format
[i
];
744 else fmt
[len
++] = format
[i
];
750 vasprintf(&str
, fmt
, ap
);
751 if (expand
!= 0) free(fmt
);
753 if (str
== NULL
) return -1;
755 status
= _asl_send_message(ac
, (asl_msg_t
*)msg
, level
, str
);
762 * asl_log: log a message with a particular log level
764 * level: the log level
765 * format: A formating string followed by a list of arguments, like printf()
766 * returns 0 for success, non-zero for failure
769 asl_log(aslclient ac
, aslmsg a
, int level
, const char *format
, ...)
774 if (format
== NULL
) return -1;
776 va_start(ap
, format
);
777 status
= asl_vlog(ac
, a
, level
, format
, ap
);
783 #ifndef BUILDING_VARIANT
786 _asl_merge_msg_aux0(asl_msg_t
*msg
, asl_msg_aux_0_t aux0
)
788 const char *key
, *val
;
791 int klevel
, ktime
, knano
, khost
, ksender
, kfac
, kpid
, kuid
, kgid
, kmsg
, kaux
, kuti
, kurl
;
793 out
= asl_msg_new(ASL_TYPE_MSG
);
794 if (out
== NULL
) return NULL
;
813 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
815 if (streq(key
, ASL_KEY_LEVEL
))
818 if (aux0
.level
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.level
);
819 else asl_msg_set_key_val(out
, key
, val
);
821 else if (streq(key
, ASL_KEY_TIME
))
824 if (aux0
.time
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.time
);
825 else asl_msg_set_key_val(out
, key
, val
);
827 else if (streq(key
, ASL_KEY_TIME_NSEC
))
830 if (aux0
.nano
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.nano
);
831 else asl_msg_set_key_val(out
, key
, val
);
833 else if (streq(key
, ASL_KEY_HOST
))
836 if (aux0
.host
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.host
);
837 else asl_msg_set_key_val(out
, key
, val
);
839 else if (streq(key
, ASL_KEY_SENDER
))
842 if (aux0
.sender
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.sender
);
843 else asl_msg_set_key_val(out
, key
, val
);
845 else if (streq(key
, ASL_KEY_FACILITY
))
848 if (aux0
.facility
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.facility
);
849 else asl_msg_set_key_val(out
, key
, val
);
851 else if (streq(key
, ASL_KEY_PID
))
854 if (aux0
.pid
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.pid
);
855 else asl_msg_set_key_val(out
, key
, val
);
857 else if (streq(key
, ASL_KEY_UID
))
860 if (aux0
.uid
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.uid
);
861 else asl_msg_set_key_val(out
, key
, val
);
863 else if (streq(key
, ASL_KEY_GID
))
866 if (aux0
.gid
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.gid
);
867 else asl_msg_set_key_val(out
, key
, val
);
869 else if (streq(key
, ASL_KEY_MSG
))
872 if (aux0
.message
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.message
);
873 else asl_msg_set_key_val(out
, key
, val
);
875 else if (streq(key
, ASL_KEY_AUX_TITLE
))
878 if (aux0
.auxtitle
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.auxtitle
);
879 else asl_msg_set_key_val(out
, key
, val
);
881 else if (streq(key
, ASL_KEY_AUX_UTI
))
884 if (aux0
.auxuti
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.auxuti
);
885 else asl_msg_set_key_val(out
, key
, val
);
887 else if (streq(key
, ASL_KEY_AUX_URL
))
890 if (aux0
.auxurl
!= NULL
) asl_msg_set_key_val(out
, key
, aux0
.auxurl
);
891 else asl_msg_set_key_val(out
, key
, val
);
895 asl_msg_set_key_val(out
, key
, val
);
899 if ((klevel
== 0) && (aux0
.level
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_LEVEL
, aux0
.level
);
900 if ((ktime
== 0) && (aux0
.time
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_TIME
, aux0
.time
);
901 if ((knano
== 0) && (aux0
.nano
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_TIME_NSEC
, aux0
.nano
);
902 if ((khost
== 0) && (aux0
.host
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_HOST
, aux0
.host
);
903 if ((ksender
== 0) && (aux0
.sender
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_SENDER
, aux0
.sender
);
904 if ((kfac
== 0) && (aux0
.facility
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_FACILITY
, aux0
.facility
);
905 if ((kpid
== 0) && (aux0
.pid
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_PID
, aux0
.pid
);
906 if ((kuid
== 0) && (aux0
.uid
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_UID
, aux0
.uid
);
907 if ((kgid
== 0) && (aux0
.gid
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_GID
, aux0
.gid
);
908 if ((kmsg
== 0) && (aux0
.message
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_MSG
, aux0
.message
);
909 if ((kaux
== 0) && (aux0
.auxtitle
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_AUX_TITLE
, aux0
.auxtitle
);
910 if ((kuti
== 0) && (aux0
.auxuti
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_AUX_UTI
, aux0
.auxuti
);
911 if ((kurl
== 0) && (aux0
.auxurl
!= NULL
)) asl_msg_set_key_val(out
, ASL_KEY_AUX_URL
, aux0
.auxurl
);
917 * asl_get_filter: gets the values for the local, master, and remote filters,
918 * and indicates which one is active.
921 asl_get_filter(aslclient ac
, int *local
, int *master
, int *remote
, int *active
)
923 asl_client_t
*asl
, *asl_default
;
933 asl_default
= _asl_open_default();
935 asl
= (asl_client_t
*)ac
;
936 if (asl
== NULL
) asl
= asl_default
;
937 if (asl
!= NULL
) l
= asl
->filter
& 0xff;
939 if ((asl_default
!= NULL
) && (!(asl_default
->options
& ASL_OPT_NO_REMOTE
)))
941 pthread_mutex_lock(&_asl_global
.lock
);
943 if (_asl_global
.rc_change_token
>= 0)
945 /* initialize or re-check process-specific and master filters */
947 status
= notify_check(_asl_global
.rc_change_token
, &check
);
948 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
950 if (_asl_global
.master_token
>= 0)
953 status
= notify_get_state(_asl_global
.master_token
, &v64
);
954 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
957 if (_asl_global
.notify_token
>= 0)
960 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
961 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
966 m
= _asl_global
.master_filter
;
969 r
= _asl_global
.proc_filter
;
972 pthread_mutex_unlock(&_asl_global
.lock
);
975 if (local
!= NULL
) *local
= l
;
976 if (master
!= NULL
) *master
= m
;
977 if (remote
!= NULL
) *remote
= r
;
978 if (active
!= NULL
) *active
= x
;
984 * asl_send: send a message
985 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
986 * has been used to set all of a message's attributes.
988 * returns 0 for success, non-zero for failure
990 __private_extern__
int
991 _asl_send_message(aslclient ac
, asl_msg_t
*msg
, int slevel
, const char *aux_message
)
994 uint32_t i
, len
, outlen
, level
, lmask
, outstatus
, filter
, fd_write
;
997 char *name
, *x
, *str
;
1000 int status
, check
, tunnel
;
1002 int use_global_lock
;
1003 kern_return_t kstatus
;
1004 char aux_level
[64], aux_time
[64], aux_nano
[64], aux_pid
[64], aux_uid
[64], aux_gid
[64];
1005 char *aux_option
, aux_host
[_POSIX_HOST_NAME_MAX
];
1007 asl_msg_aux_0_t aux0
;
1009 use_global_lock
= 0;
1010 asl
= (asl_client_t
*)ac
;
1013 asl
= _asl_open_default();
1014 if (asl
== NULL
) return -1;
1015 use_global_lock
= 1;
1018 if (asl
->aslfile
!= NULL
)
1020 use_global_lock
= 1;
1023 level
= ASL_LEVEL_DEBUG
;
1024 if (slevel
>= 0) level
= slevel
;
1026 val
= asl_get((aslmsg
)msg
, ASL_KEY_LEVEL
);
1030 if (check
< ASL_LEVEL_EMERG
) check
= ASL_LEVEL_EMERG
;
1031 else if (check
> ASL_LEVEL_DEBUG
) check
= ASL_LEVEL_DEBUG
;
1035 lmask
= ASL_FILTER_MASK(level
);
1037 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
1039 pthread_mutex_lock(&_asl_global
.lock
);
1041 if (_asl_global
.rc_change_token
>= 0)
1043 /* initialize or re-check process-specific and master filters */
1045 status
= notify_check(_asl_global
.rc_change_token
, &check
);
1046 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
1048 if (_asl_global
.master_token
>= 0)
1051 status
= notify_get_state(_asl_global
.master_token
, &v64
);
1052 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
1055 if (_asl_global
.notify_token
>= 0)
1058 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
1059 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
1064 pthread_mutex_unlock(&_asl_global
.lock
);
1067 filter
= asl
->filter
& 0xff;
1068 tunnel
= (asl
->filter
& ASL_FILTER_MASK_TUNNEL
) >> 8;
1070 /* master filter overrides local filter */
1071 if (_asl_global
.master_filter
!= 0)
1073 filter
= _asl_global
.master_filter
;
1077 /* process-specific filter overrides local and master */
1078 if (_asl_global
.proc_filter
!= 0)
1080 filter
= _asl_global
.proc_filter
;
1085 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here.
1086 * Also sets Sender & Facility (if unset) and "ASLOption store" if remote control is active.
1089 aux
.type
= ASL_MSG_TYPE_AUX_0
;
1091 memset(&aux0
, 0, sizeof(asl_msg_aux_0_t
));
1092 aux
.data
.aux0
= &aux0
;
1094 aux0
.message
= aux_message
;
1096 snprintf(aux_level
, sizeof(aux_level
), "%u", level
);
1097 aux0
.level
= aux_level
;
1099 memset(&tval
, 0, sizeof(struct timeval
));
1101 status
= gettimeofday(&tval
, NULL
);
1104 snprintf(aux_time
, sizeof(aux_time
), "%lu", tval
.tv_sec
);
1105 snprintf(aux_nano
, sizeof(aux_nano
), "%d", tval
.tv_usec
* 1000);
1106 aux0
.time
= aux_time
;
1107 aux0
.nano
= aux_nano
;
1112 snprintf(aux_time
, sizeof(aux_time
), "%lu", tick
);
1113 aux0
.time
= aux_time
;
1116 memset(&aux_host
, 0, _POSIX_HOST_NAME_MAX
);
1117 if (gethostname(aux_host
, _POSIX_HOST_NAME_MAX
) == 0)
1119 aux0
.host
= aux_host
;
1122 snprintf(aux_pid
, sizeof(aux_pid
), "%u", getpid());
1125 snprintf(aux_uid
, sizeof(aux_uid
), "%d", getuid());
1128 snprintf(aux_gid
, sizeof(aux_uid
), "%d", getgid());
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 aux0
.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
) aux0
.sender
= _asl_global
.sender
;
1161 else aux0
.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 aux0
.facility
= ac
->facility
;
1178 /* Set "ASLOption store" if remote control is active */
1184 val
= asl_get((aslmsg
)msg
, ASL_KEY_OPTION
);
1187 aux0
.option
= ASL_OPT_STORE
;
1191 asprintf(&aux_option
, "%s %s", ASL_OPT_STORE
, val
);
1192 aux0
.option
= aux_option
;
1198 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
1201 * If there is an aslfile this is a stand-alone file client.
1202 * Just save to the file.
1204 if (asl
->aslfile
!= NULL
)
1206 asl_msg_t
*merged_msg
;
1208 outstatus
= ASL_STATUS_FAILED
;
1210 merged_msg
= _asl_merge_msg_aux0(msg
, aux0
);
1211 if (merged_msg
!= NULL
)
1213 outstatus
= asl_file_save(asl
->aslfile
, (aslmsg
)merged_msg
, &(asl
->aslfileid
));
1215 asl_msg_release(merged_msg
);
1218 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1223 if ((_asl_global
.server_port
!= MACH_PORT_NULL
) && (filter
!= 0) && ((filter
& lmask
) != 0))
1225 len
= _asl_msg_string_length_aux(msg
, &aux
);
1229 /* send a mach message to syslogd */
1232 kstatus
= vm_allocate(mach_task_self(), &out
, outlen
, TRUE
);
1233 if (kstatus
== KERN_SUCCESS
)
1235 memset((void *)out
, 0, outlen
);
1236 snprintf((char *)out
, 12, "%10u ", len
);
1238 status
= _asl_msg_to_string_buffer_aux(msg
, &aux
, (char *)(out
+ 11), len
);
1241 if (kstatus
== KERN_SUCCESS
) kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)out
, outlen
);
1242 else vm_deallocate(mach_task_self(), out
, outlen
);
1244 if (kstatus
== KERN_SUCCESS
) outstatus
= 0;
1248 vm_deallocate(mach_task_self(), (vm_address_t
)out
, outlen
);
1254 if (aux_option
!= NULL
) free(aux_option
);
1259 /* messages from syslog() get filtered on the way out to stderr */
1261 if ((asl
->options
& ASL_OPT_SYSLOG_LEGACY
) && (filter
!= 0) && ((filter
& lmask
) == 0)) fd_write
= 0;
1263 if ((fd_write
!= 0) && (asl
->fd_count
> 0))
1265 asl_msg_t
*merged_msg
;
1268 * It's easier to merge the aux fields with the msg into a new message
1269 * than to have asl_format_messge deal with two inputs. Since this is
1270 * an infrequently used code path, we pay a small price to merge them
1271 * here and save a lot of code complexity.
1274 merged_msg
= _asl_merge_msg_aux0(msg
, aux0
);
1275 if (merged_msg
!= NULL
)
1277 /* write to file descriptors */
1279 for (i
= 0; i
< asl
->fd_count
; i
++)
1281 if (asl
->fd_list
[i
] < 0) continue;
1284 str
= asl_format_message(merged_msg
, asl
->fd_mfmt
[i
], asl
->fd_tfmt
[i
], asl
->fd_encoding
[i
], &len
);
1285 if (str
== NULL
) continue;
1287 status
= write(asl
->fd_list
[i
], str
, len
- 1);
1290 asl
->fd_list
[i
] = -1;
1297 asl_msg_release(merged_msg
);
1301 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1307 asl_send(aslclient ac
, aslmsg msg
)
1309 return _asl_send_message(ac
, (asl_msg_t
*)msg
, -1, NULL
);
1313 _asl_aux_save_context(asl_aux_context_t
*ctx
)
1315 if (ctx
== NULL
) return -1;
1317 pthread_mutex_lock(&_asl_global
.lock
);
1319 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count
+ 1) * sizeof(asl_aux_context_t
*));
1320 if (_asl_global
.aux_ctx
== NULL
)
1322 _asl_global
.aux_count
= 0;
1326 _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
;
1328 pthread_mutex_unlock(&_asl_global
.lock
);
1334 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1335 * will be saved at the time that the auxiliary file is created. The message will include
1336 * any keys and values found in msg, and it will include the title and Uniform Type
1337 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1338 * new auxiliary file.
1341 _asl_auxiliary(aslmsg msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
)
1343 asl_msg_t
*merged_msg
;
1345 asl_msg_aux_0_t aux0
;
1346 fileport_t fileport
;
1347 kern_return_t kstatus
;
1348 uint32_t outlen
, newurllen
, len
, where
;
1349 int status
, fd
, fdpair
[2];
1350 caddr_t out
, newurl
;
1351 dispatch_queue_t pipe_q
;
1352 dispatch_io_t pipe_channel
;
1353 dispatch_semaphore_t sem
;
1355 aux
.type
= ASL_MSG_TYPE_AUX_0
;
1357 memset(&aux0
, 0, sizeof(asl_msg_aux_0_t
));
1358 aux
.data
.aux0
= &aux0
;
1360 aux0
.auxtitle
= title
;
1361 if (uti
== NULL
) aux0
.auxuti
= "public.data";
1362 else aux0
.auxuti
= uti
;
1365 merged_msg
= _asl_merge_msg_aux0((asl_msg_t
*)msg
, aux0
);
1366 if (merged_msg
== NULL
) return -1;
1368 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1371 status
= _asl_send_message(NULL
, merged_msg
, -1, NULL
);
1372 asl_msg_release(merged_msg
);
1376 where
= asl_store_location();
1378 if (where
== ASL_STORE_LOCATION_MEMORY
)
1382 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1383 if (ctx
== NULL
) return -1;
1385 status
= pipe(fdpair
);
1392 /* give read end to dispatch_io_read */
1394 sem
= dispatch_semaphore_create(0);
1396 ctx
->fd
= fdpair
[1];
1398 status
= _asl_aux_save_context(ctx
);
1403 dispatch_release(sem
);
1408 pipe_q
= dispatch_queue_create("PipeQ", NULL
);
1409 pipe_channel
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){
1413 *out_fd
= fdpair
[1];
1415 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
);
1417 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){
1420 size_t len
= dispatch_data_get_size(pipedata
);
1423 const char *bytes
= NULL
;
1426 dispatch_data_t md
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
);
1427 encoded
= asl_core_encode_buffer(bytes
, len
);
1428 asl_set((aslmsg
)merged_msg
, ASL_KEY_AUX_DATA
, encoded
);
1430 _asl_send_message(NULL
, merged_msg
, -1, NULL
);
1431 asl_msg_release(merged_msg
);
1432 dispatch_release(md
);
1438 dispatch_semaphore_signal(sem
);
1439 dispatch_release(pipe_channel
);
1440 dispatch_release(pipe_q
);
1448 if (_asl_global
.server_port
== MACH_PORT_NULL
) return -1;
1450 len
= _asl_msg_string_length_aux(merged_msg
, NULL
);
1453 asl_msg_release(merged_msg
);
1458 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&out
, outlen
, TRUE
);
1459 if (kstatus
!= KERN_SUCCESS
)
1461 asl_msg_release(merged_msg
);
1465 memset(out
, 0, outlen
);
1466 snprintf((char *)out
, 12, "%10u ", len
);
1468 status
= _asl_msg_to_string_buffer_aux(merged_msg
, NULL
, (char *)(out
+ 11), len
);
1471 asl_msg_release(merged_msg
);
1472 vm_deallocate(mach_task_self(), (vm_address_t
)out
, outlen
);
1477 fileport
= MACH_PORT_NULL
;
1478 status
= KERN_SUCCESS
;
1480 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, out
, outlen
, &fileport
, &newurl
, &newurllen
, &status
);
1481 if (kstatus
!= KERN_SUCCESS
)
1483 asl_msg_release(merged_msg
);
1489 asl_msg_release(merged_msg
);
1495 asl_msg_set_key_val(merged_msg
, ASL_KEY_AUX_URL
, newurl
);
1496 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
);
1499 if (fileport
== MACH_PORT_NULL
)
1501 asl_msg_release(merged_msg
);
1505 fd
= fileport_makefd(fileport
);
1506 mach_port_deallocate(mach_task_self(), fileport
);
1509 asl_msg_release(merged_msg
);
1514 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1524 ctx
->msg
= merged_msg
;
1526 status
= _asl_aux_save_context(ctx
);
1534 asl_create_auxiliary_file(aslmsg msg
, const char *title
, const char *uti
, int *out_fd
)
1536 if (out_fd
== NULL
) return -1;
1538 return _asl_auxiliary(msg
, title
, uti
, NULL
, out_fd
);
1542 asl_log_auxiliary_location(aslmsg msg
, const char *title
, const char *uti
, const char *url
)
1544 return _asl_auxiliary(msg
, title
, uti
, url
, NULL
);
1548 * Close an auxiliary file.
1549 * Sends the cached auxiliary message to syslogd.
1552 asl_close_auxiliary_file(int fd
)
1556 dispatch_semaphore_t aux_sem
;
1558 pthread_mutex_lock(&(_asl_global
.lock
));
1563 for (i
= 0; i
< _asl_global
.aux_count
; i
++)
1565 if (_asl_global
.aux_ctx
[i
]->fd
== fd
)
1569 aux_msg
= _asl_global
.aux_ctx
[i
]->msg
;
1570 aux_sem
= _asl_global
.aux_ctx
[i
]->sem
;
1572 free(_asl_global
.aux_ctx
[i
]);
1574 for (j
= i
+ 1; j
< _asl_global
.aux_count
; i
++, j
++)
1576 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
];
1579 _asl_global
.aux_count
--;
1581 if (_asl_global
.aux_count
== 0)
1583 free(_asl_global
.aux_ctx
);
1584 _asl_global
.aux_ctx
= NULL
;
1588 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count
* sizeof(asl_aux_context_t
*));
1589 if (_asl_global
.aux_ctx
== NULL
)
1591 _asl_global
.aux_count
= 0;
1600 pthread_mutex_unlock(&(_asl_global
.lock
));
1604 if (aux_msg
!= NULL
)
1606 if (_asl_send_message(NULL
, aux_msg
, -1, NULL
) != ASL_STATUS_OK
) status
= -1;
1607 asl_msg_release(aux_msg
);
1610 if (aux_sem
!= NULL
)
1612 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
);
1613 dispatch_release(aux_sem
);
1620 * asl_search: Search for messages matching the criteria described
1621 * by the aslmsg. The caller should set the attributes to match using
1622 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
1623 * used for attributes set with asl_set().
1625 * returns: a set of messages that can be iterated over using aslresp_next(),
1626 * and the values can be retrieved using aslresp_get.
1630 * This routine searches the ASL datastore on disk (/var/log/asl).
1631 * It is called my asl_search if syslogd is not running or if syslogd
1632 * indicates that an in-memory store is not being used.
1635 _asl_search_store(aslclient ac
, aslmsg a
)
1637 asl_search_result_t query
, *out
;
1638 asl_msg_t
*q
, *qlist
[1];
1639 uint32_t status
, op
;
1640 uint64_t last_id
, start_id
;
1644 if (a
== NULL
) return NULL
;
1648 /* check for "ASLMessageId >[=] n" and set start_id */
1652 status
= asl_msg_lookup(q
, ASL_KEY_MSG_ID
, &val
, &op
);
1653 if ((status
== 0) && (val
!= NULL
) && (op
& ASL_QUERY_OP_GREATER
))
1655 if (op
& ASL_QUERY_OP_EQUAL
) start_id
= atoll(val
);
1656 else start_id
= atoll(val
) + 1;
1660 status
= asl_store_open_read(NULL
, &store
);
1661 if (status
!= 0) return NULL
;
1662 if (store
== NULL
) return NULL
;
1667 qlist
[0] = (asl_msg_t
*)a
;
1668 memset(&query
, 0, sizeof(asl_search_result_t
));
1672 status
= asl_store_match(store
, &query
, &out
, &last_id
, start_id
, 0, 1);
1673 asl_store_close(store
);
1679 _asl_search_concat_results(asl_search_result_t
*batch
, asl_search_result_t
**out
)
1683 if (out
== NULL
) return ASL_STATUS_FAILED
;
1685 /* nothing to do if batch is NULL or contains no messages */
1686 if (batch
== NULL
) return 0;
1687 if (batch
->count
== 0)
1689 aslresponse_free(batch
);
1693 if (*out
== NULL
) *out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
1696 aslresponse_free(batch
);
1697 return ASL_STATUS_FAILED
;
1700 if ((*out
)->count
== 0)
1702 (*out
)->msg
= (asl_msg_t
**)calloc(batch
->count
, sizeof(asl_msg_t
*));
1706 (*out
)->msg
= (asl_msg_t
**)reallocf((*out
)->msg
, ((*out
)->count
+ batch
->count
) * sizeof(asl_msg_t
*));
1709 if ((*out
)->msg
== NULL
)
1711 aslresponse_free(batch
);
1714 return ASL_STATUS_FAILED
;
1717 for (i
= 0, j
= (*out
)->count
; i
< batch
->count
; i
++, j
++) (*out
)->msg
[j
] = batch
->msg
[i
];
1719 (*out
)->count
+= batch
->count
;
1722 return ASL_STATUS_OK
;
1726 _asl_search_memory(aslclient ac
, aslmsg a
)
1728 asl_search_result_t
*batch
, *out
;
1729 char *qstr
, *str
, *res
;
1730 uint32_t len
, reslen
, status
;
1731 uint64_t cmax
, qmin
;
1732 kern_return_t kstatus
;
1733 security_token_t sec
;
1736 if (a
== NULL
) return 0;
1739 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1742 qstr
= asl_msg_to_string((asl_msg_t
*)a
, &len
);
1747 asprintf(&str
, "0\n");
1752 asprintf(&str
, "1\n%s\n", qstr
);
1757 if (str
== NULL
) return NULL
;
1760 * Fetch a batch of results each time through the loop.
1761 * Fetching small batches rebuces the load on syslogd.
1773 status
= ASL_STATUS_OK
;
1775 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
1776 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1778 memmove(vmstr
, str
, len
);
1781 kstatus
= _asl_server_query(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1782 if (kstatus
!= KERN_SUCCESS
) break;
1783 if (res
== NULL
) break;
1785 batch
= asl_list_from_string(res
);
1786 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1788 status
= _asl_search_concat_results(batch
, &out
);
1789 if (status
!= ASL_STATUS_OK
) break;
1790 if (out
->count
< FETCH_BATCH
) break;
1792 if (cmax
>= qmin
) qmin
= cmax
+ 1;
1801 asl_store_location()
1803 kern_return_t kstatus
;
1805 uint32_t reslen
, status
;
1807 security_token_t sec
;
1810 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
1817 status
= ASL_STATUS_OK
;
1819 kstatus
= _asl_server_query(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
1821 /* res should never be returned, but just to be certain we don't leak VM ... */
1822 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1824 if (kstatus
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
;
1826 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
1827 return ASL_STORE_LOCATION_FILE
;
1831 asl_search(aslclient ac
, aslmsg a
)
1834 asl_search_result_t
*out
;
1838 where
= asl_store_location();
1839 if (where
== ASL_STORE_LOCATION_FILE
) out
= _asl_search_store(ac
, a
);
1840 else out
= _asl_search_memory(ac
, a
);
1846 asl_syslog_faciliy_name_to_num(const char *name
)
1848 if (name
== NULL
) return -1;
1850 if (strcaseeq(name
, "auth")) return LOG_AUTH
;
1851 if (strcaseeq(name
, "authpriv")) return LOG_AUTHPRIV
;
1852 if (strcaseeq(name
, "cron")) return LOG_CRON
;
1853 if (strcaseeq(name
, "daemon")) return LOG_DAEMON
;
1854 if (strcaseeq(name
, "ftp")) return LOG_FTP
;
1855 if (strcaseeq(name
, "install")) return LOG_INSTALL
;
1856 if (strcaseeq(name
, "kern")) return LOG_KERN
;
1857 if (strcaseeq(name
, "lpr")) return LOG_LPR
;
1858 if (strcaseeq(name
, "mail")) return LOG_MAIL
;
1859 if (strcaseeq(name
, "netinfo")) return LOG_NETINFO
;
1860 if (strcaseeq(name
, "remoteauth")) return LOG_REMOTEAUTH
;
1861 if (strcaseeq(name
, "news")) return LOG_NEWS
;
1862 if (strcaseeq(name
, "security")) return LOG_AUTH
;
1863 if (strcaseeq(name
, "syslog")) return LOG_SYSLOG
;
1864 if (strcaseeq(name
, "user")) return LOG_USER
;
1865 if (strcaseeq(name
, "uucp")) return LOG_UUCP
;
1866 if (strcaseeq(name
, "local0")) return LOG_LOCAL0
;
1867 if (strcaseeq(name
, "local1")) return LOG_LOCAL1
;
1868 if (strcaseeq(name
, "local2")) return LOG_LOCAL2
;
1869 if (strcaseeq(name
, "local3")) return LOG_LOCAL3
;
1870 if (strcaseeq(name
, "local4")) return LOG_LOCAL4
;
1871 if (strcaseeq(name
, "local5")) return LOG_LOCAL5
;
1872 if (strcaseeq(name
, "local6")) return LOG_LOCAL6
;
1873 if (strcaseeq(name
, "local7")) return LOG_LOCAL7
;
1874 if (strcaseeq(name
, "launchd")) return LOG_LAUNCHD
;
1880 asl_syslog_faciliy_num_to_name(int n
)
1882 if (n
< 0) return NULL
;
1884 if (n
== LOG_AUTH
) return "auth";
1885 if (n
== LOG_AUTHPRIV
) return "authpriv";
1886 if (n
== LOG_CRON
) return "cron";
1887 if (n
== LOG_DAEMON
) return "daemon";
1888 if (n
== LOG_FTP
) return "ftp";
1889 if (n
== LOG_INSTALL
) return "install";
1890 if (n
== LOG_KERN
) return "kern";
1891 if (n
== LOG_LPR
) return "lpr";
1892 if (n
== LOG_MAIL
) return "mail";
1893 if (n
== LOG_NETINFO
) return "netinfo";
1894 if (n
== LOG_REMOTEAUTH
) return "remoteauth";
1895 if (n
== LOG_NEWS
) return "news";
1896 if (n
== LOG_AUTH
) return "security";
1897 if (n
== LOG_SYSLOG
) return "syslog";
1898 if (n
== LOG_USER
) return "user";
1899 if (n
== LOG_UUCP
) return "uucp";
1900 if (n
== LOG_LOCAL0
) return "local0";
1901 if (n
== LOG_LOCAL1
) return "local1";
1902 if (n
== LOG_LOCAL2
) return "local2";
1903 if (n
== LOG_LOCAL3
) return "local3";
1904 if (n
== LOG_LOCAL4
) return "local4";
1905 if (n
== LOG_LOCAL5
) return "local5";
1906 if (n
== LOG_LOCAL6
) return "local6";
1907 if (n
== LOG_LOCAL7
) return "local7";
1908 if (n
== LOG_LAUNCHD
) return "launchd";
1914 * utility for converting a time string into a time_t
1915 * we only deal with the following formats:
1916 * Canonical form YYYY.MM.DD hh:mm:ss UTC
1917 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
1918 * absolute form - # seconds since the epoch (e.g. 1095789191)
1919 * relative time - seconds before or after now (e.g. -300, +43200)
1920 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
1923 #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$"
1924 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
1925 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
1926 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
1928 #define SECONDS_PER_MINUTE 60
1929 #define SECONDS_PER_HOUR 3600
1930 #define SECONDS_PER_DAY 86400
1931 #define SECONDS_PER_WEEK 604800
1933 static regex_t rex_canon
, rex_ctime
, rex_abs
, rex_rel
;
1934 static int reg_status
= 0;
1937 * We use the last letter in the month name to determine
1938 * the month number (0-11). There are two collisions:
1939 * Jan and Jun both end in n
1940 * Mar and Apr both end in r
1941 * In these cases we check the second letter.
1943 * The MTH_LAST array maps the last letter to a number.
1945 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};
1954 if (s
[2] > 90) v8
= s
[2] - 'a';
1955 else v8
= s
[2] - 'A';
1957 if ((v8
< 0) || (v8
> 25)) return -1;
1960 if (v8
< 0) return -1;
1963 if ((i
== 5) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 0;
1964 if ((i
== 3) && ((s
[1] == 'a') || (s
[1] == 'A'))) return 2;
1969 asl_parse_time(const char *in
)
1973 time_t tick
, delta
, factor
;
1975 static dispatch_once_t once
;
1977 if (in
== NULL
) return -1;
1979 dispatch_once(&once
, ^{
1981 int rflags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
1983 memset(&rex_canon
, 0, sizeof(regex_t
));
1984 status
= regcomp(&rex_canon
, CANONICAL_TIME_REX
, rflags
);
1985 if (status
!= 0) reg_status
= -1;
1987 memset(&rex_ctime
, 0, sizeof(regex_t
));
1988 status
= regcomp(&rex_ctime
, CTIME_REX
, rflags
);
1989 if (status
!= 0) reg_status
= -1;
1991 memset(&rex_abs
, 0, sizeof(regex_t
));
1992 status
= regcomp(&rex_abs
, ABSOLUTE_TIME_REX
, rflags
);
1993 if (status
!= 0) reg_status
= -1;
1995 memset(&rex_rel
, 0, sizeof(regex_t
));
1996 status
= regcomp(&rex_rel
, RELATIVE_TIME_REX
, rflags
);
1997 if (status
!= 0) reg_status
= -1;
2000 if (reg_status
< 0) return -1;
2002 len
= strlen(in
) + 1;
2004 if (regexec(&rex_abs
, in
, 0, NULL
, 0) == 0)
2007 * Absolute time (number of seconds since the epoch)
2010 if (str
== NULL
) return -1;
2012 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S')) str
[len
-2] = '\0';
2019 else if (regexec(&rex_rel
, in
, 0, NULL
, 0) == 0)
2022 * Reletive time (number of seconds before or after right now)
2025 if (str
== NULL
) return -1;
2029 if ((str
[len
-2] == 's') || (str
[len
-2] == 'S'))
2033 else if ((str
[len
-2] == 'm') || (str
[len
-2] == 'M'))
2036 factor
= SECONDS_PER_MINUTE
;
2038 else if ((str
[len
-2] == 'h') || (str
[len
-2] == 'H'))
2041 factor
= SECONDS_PER_HOUR
;
2043 else if ((str
[len
-2] == 'd') || (str
[len
-2] == 'D'))
2046 factor
= SECONDS_PER_DAY
;
2048 else if ((str
[len
-2] == 'w') || (str
[len
-2] == 'W'))
2051 factor
= SECONDS_PER_WEEK
;
2055 delta
= factor
* atol(str
);
2062 else if (regexec(&rex_canon
, in
, 0, NULL
, 0) == 0)
2064 memset(&t
, 0, sizeof(struct tm
));
2066 if (str
== NULL
) return -1;
2072 t
.tm_year
= atoi(x
) - 1900;
2078 t
.tm_mon
= atoi(x
) - 1;
2084 t
.tm_mday
= atoi(x
);
2087 for (x
= p
+ 1; *x
== ' '; x
++);
2090 t
.tm_hour
= atoi(x
);
2107 else if (regexec(&rex_ctime
, in
, 0, NULL
, 0) == 0)
2109 /* We assume it's in the current year */
2110 memset(&t
, 0, sizeof(struct tm
));
2112 gmtime_r(&tick
, &t
);
2115 memset(&t
, 0, sizeof(struct tm
));
2117 if (str
== NULL
) return -1;
2120 t
.tm_mon
= _month_num(str
);
2121 if (t
.tm_mon
< 0) return -1;
2123 for (x
= strchr(str
, ' '); *x
== ' '; x
++);
2126 t
.tm_mday
= atoi(x
);
2129 for (x
= p
+ 1; *x
== ' '; x
++);
2132 t
.tm_hour
= atoi(x
);
2153 #endif /* BUILDING_VARIANT */