2 * Copyright (c) 2013 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/types.h>
37 #include <libkern/OSAtomic.h>
38 #include <crt_externs.h>
40 #include <asl_private.h>
43 #include <asl_client.h>
45 #define PUBLIC_OPT_MASK 0x000000ff
47 /* private asl_file SPI */
48 __private_extern__ ASL_STATUS
asl_file_open_write_fd(int descriptor
, asl_file_t
**s
);
51 __private_extern__ ASL_STATUS
asl_client_internal_send(asl_object_t client
, asl_object_t msg
);
54 #pragma mark asl_client_t
57 _asl_client_free_internal(asl_client_t
*client
)
61 if (client
== NULL
) return;
63 if (client
->kvdict
!= NULL
) asl_msg_release(client
->kvdict
);
64 client
->kvdict
= NULL
;
66 if (client
->aslfile
!= NULL
) asl_file_close(client
->aslfile
);
67 client
->aslfile
= NULL
;
69 for (i
= 0; i
< client
->out_count
; i
++)
71 free(client
->out_list
[i
].mfmt
);
72 free(client
->out_list
[i
].tfmt
);
75 free(client
->out_list
);
76 client
->out_list
= NULL
;
82 asl_client_open(const char *ident
, const char *facility
, uint32_t opts
)
84 asl_client_t
*client
= (asl_client_t
*)calloc(1, sizeof(asl_client_t
));
91 client
->asl_type
= ASL_TYPE_CLIENT
;
94 client
->kvdict
= asl_msg_new(ASL_TYPE_MSG
);
95 if (client
->kvdict
== NULL
)
97 asl_client_release(client
);
102 client
->options
= opts
& PUBLIC_OPT_MASK
;
104 client
->pid
= getpid();
105 client
->uid
= getuid();
106 client
->gid
= getgid();
110 asl_msg_set_key_val(client
->kvdict
, ASL_KEY_SENDER
, ident
);
114 char *name
= *(*_NSGetArgv());
117 char *x
= strrchr(name
, '/');
120 asl_msg_set_key_val(client
->kvdict
, ASL_KEY_SENDER
, x
);
124 if (facility
!= NULL
)
126 asl_msg_set_key_val(client
->kvdict
, ASL_KEY_FACILITY
, facility
);
128 else if (client
->uid
== 0)
130 asl_msg_set_key_val(client
->kvdict
, ASL_KEY_FACILITY
, asl_syslog_faciliy_num_to_name(LOG_DAEMON
));
134 asl_msg_set_key_val(client
->kvdict
, ASL_KEY_FACILITY
, asl_syslog_faciliy_num_to_name(LOG_USER
));
137 client
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE
);
139 if (client
->options
& ASL_OPT_STDERR
)
141 /* only add stderr if it is valid */
142 if (fcntl(STDERR_FILENO
, F_GETFD
) >= 0)
144 asl_client_add_output_file(client
, fileno(stderr
), ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), ASL_ENCODE_SAFE
);
148 /* stderr has been closed, ignore ASL_OPT_STDERR flag */
149 client
->options
&= ~ASL_OPT_STDERR
;
157 asl_client_open_from_file(int descriptor
, const char *ident
, const char *facility
)
160 asl_client_t
*client
= asl_client_open(ident
, facility
, 0);
161 if (client
== NULL
) return NULL
;
163 client
->filter
= ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
);
165 status
= asl_file_open_write_fd(descriptor
, &(client
->aslfile
));
166 if (status
!= ASL_STATUS_OK
)
168 _asl_client_free_internal(client
);
172 client
->aslfileid
= 1;
178 asl_client_retain(asl_client_t
*client
)
180 if (client
== NULL
) return NULL
;
181 asl_retain((asl_object_t
)client
);
186 asl_client_release(asl_client_t
*client
)
188 if (client
== NULL
) return;
189 asl_release((asl_object_t
)client
);
193 #pragma mark database access
196 asl_client_send(asl_client_t
*client
, asl_msg_t
*msg
)
198 return asl_client_internal_send((asl_object_t
)client
, (asl_object_t
)msg
);
201 static asl_msg_list_t
*
202 _do_server_match(asl_msg_list_t
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int dir
)
204 char *str
, *res
= NULL
;
205 uint32_t len
, reslen
, status
;
206 uint64_t last64
, start64
, count64
;
207 kern_return_t kstatus
;
210 mach_port_t asl_server_port
= asl_core_get_service_port(0);
212 if (asl_server_port
== MACH_PORT_NULL
) return NULL
;
217 asprintf(&str
, "0\n");
222 str
= asl_msg_list_to_string(qlist
, &len
);
225 if (str
== NULL
) return NULL
;
227 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
228 if (kstatus
!= KERN_SUCCESS
) return NULL
;
230 memmove(vmstr
, str
, len
);
237 kstatus
= _asl_server_match(asl_server_port
, vmstr
, len
, start64
, count64
, duration
, dir
, (caddr_t
*)&res
, &reslen
, &last64
, (int *)&status
);
240 out
= asl_msg_list_from_string(res
);
241 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
246 static asl_msg_list_t
*
247 _do_server_search(asl_msg_t
*q
)
250 char *qstr
, *str
, *res
= NULL
;
251 uint32_t len
, reslen
= 0, status
= ASL_STATUS_OK
;
253 kern_return_t kstatus
;
255 mach_port_t asl_server_port
= asl_core_get_service_port(0);
257 if (asl_server_port
== MACH_PORT_NULL
) return NULL
;
260 qstr
= asl_msg_to_string(q
, &len
);
265 asprintf(&str
, "0\n");
270 asprintf(&str
, "1\n%s\n", qstr
);
275 if (str
== NULL
) return NULL
;
277 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
278 if (kstatus
!= KERN_SUCCESS
) return NULL
;
280 memmove(vmstr
, str
, len
);
283 kstatus
= _asl_server_query_2(asl_server_port
, vmstr
, len
, 0, 0, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
284 if (kstatus
!= KERN_SUCCESS
) return NULL
;
286 out
= asl_msg_list_from_string(res
);
287 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
292 static asl_msg_list_t
*
293 _do_store_match(asl_msg_list_t
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int32_t direction
)
297 uint64_t l64
= 0, s64
;
298 asl_store_t
*store
= NULL
;
301 char *str
= asl_msg_list_to_string(qlist
, &len
);
304 status
= asl_store_open_read(NULL
, &store
);
305 if (status
!= 0) return NULL
;
306 if (store
== NULL
) return NULL
;
309 out
= asl_store_match(store
, qlist
, &l64
, s64
, count
, duration
, direction
);
312 asl_store_close(store
);
317 static asl_msg_list_t
*
318 _do_store_search(asl_msg_t
*query
)
320 asl_msg_list_t
*out
, *qlist
= NULL
;
323 uint64_t last
= 0, start
= 0;
324 asl_store_t
*store
= NULL
;
325 const char *val
= NULL
;
327 /* check for "ASLMessageId >[=] n" and set start_id */
328 status
= asl_msg_lookup(query
, ASL_KEY_MSG_ID
, &val
, &op
);
329 if ((status
== 0) && (val
!= NULL
) && (op
& ASL_QUERY_OP_GREATER
))
331 if (op
& ASL_QUERY_OP_EQUAL
) start
= atoll(val
);
332 else start
= atoll(val
) + 1;
335 status
= asl_store_open_read(NULL
, &store
);
336 if (status
!= 0) return NULL
;
337 if (store
== NULL
) return NULL
;
341 qlist
= asl_msg_list_new();
342 asl_msg_list_append(qlist
, query
);
345 out
= asl_store_match(store
, qlist
, &last
, start
, 0, 0, 1);
346 asl_store_close(store
);
348 asl_msg_list_release(qlist
);
353 asl_client_match(asl_client_t
*client
, asl_msg_list_t
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int32_t direction
)
355 if (asl_store_location() == ASL_STORE_LOCATION_FILE
) return _do_store_match(qlist
, last
, start
, count
, duration
, direction
);
356 return _do_server_match(qlist
, last
, start
, count
, duration
, direction
);
360 asl_client_search(asl_client_t
*client
, asl_msg_t
*query
)
362 if (asl_store_location() == ASL_STORE_LOCATION_FILE
) return _do_store_search(query
);
363 return _do_server_search(query
);
368 #pragma mark output control
370 /* returns last filter value, or -1 on error */
372 asl_client_set_filter(asl_client_t
*client
, int filter
)
376 if (client
== NULL
) return -1;
377 last
= client
->filter
;
378 client
->filter
= filter
;
383 asl_client_add_output_file(asl_client_t
*client
, int descriptor
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
)
387 if (client
== NULL
) return ASL_STATUS_FAILED
;
389 for (i
= 0; i
< client
->out_count
; i
++)
391 if (client
->out_list
[i
].fd
== descriptor
)
393 /* update message format, time format, filter, and text encoding */
394 free(client
->out_list
[i
].mfmt
);
395 client
->out_list
[i
].mfmt
= NULL
;
396 if (mfmt
!= NULL
) client
->out_list
[i
].mfmt
= strdup(mfmt
);
398 free(client
->out_list
[i
].tfmt
);
399 client
->out_list
[i
].tfmt
= NULL
;
400 if (tfmt
!= NULL
) client
->out_list
[i
].tfmt
= strdup(tfmt
);
402 client
->out_list
[i
].encoding
= text_encoding
;
403 client
->out_list
[i
].filter
= filter
;
405 return ASL_STATUS_OK
;
409 if (client
->out_count
== 0) client
->out_list
= NULL
;
410 client
->out_list
= (asl_out_file_t
*)reallocf(client
->out_list
, (1 + client
->out_count
) * sizeof(asl_out_file_t
));
412 if (client
->out_list
== NULL
) return ASL_STATUS_FAILED
;
414 client
->out_list
[client
->out_count
].fd
= descriptor
;
415 client
->out_list
[client
->out_count
].encoding
= text_encoding
;
416 client
->out_list
[client
->out_count
].filter
= filter
;
417 if (mfmt
!= NULL
) client
->out_list
[client
->out_count
].mfmt
= strdup(mfmt
);
418 if (tfmt
!= NULL
) client
->out_list
[client
->out_count
].tfmt
= strdup(tfmt
);
422 return ASL_STATUS_OK
;
425 /* returns last filter value, or -1 on error */
427 asl_client_set_output_file_filter(asl_client_t
*client
, int descriptor
, int filter
)
432 if (client
== NULL
) return -1;
434 for (i
= 0; i
< client
->out_count
; i
++)
436 if (client
->out_list
[i
].fd
== descriptor
)
439 last
= client
->out_list
[i
].filter
;
440 client
->out_list
[i
].filter
= filter
;
449 asl_client_remove_output_file(asl_client_t
*client
, int descriptor
)
454 if (client
== NULL
) return ASL_STATUS_INVALID_ARG
;
456 if (client
->out_count
== 0) return ASL_STATUS_OK
;
459 for (i
= 0; i
< client
->out_count
; i
++)
461 if (client
->out_list
[i
].fd
== descriptor
)
468 if (x
== -1) return ASL_STATUS_OK
;
470 free(client
->out_list
[x
].mfmt
);
471 free(client
->out_list
[x
].tfmt
);
473 for (i
= x
+ 1; i
< client
->out_count
; i
++, x
++)
475 client
->out_list
[x
] = client
->out_list
[i
];
480 if (client
->out_count
== 0)
482 free(client
->out_list
);
483 client
->out_list
= NULL
;
487 client
->out_list
= (asl_out_file_t
*)reallocf(client
->out_list
, client
->out_count
* sizeof(asl_out_file_t
));
489 if (client
->out_list
== NULL
)
491 client
->out_count
= 0;
492 return ASL_STATUS_FAILED
;
496 return ASL_STATUS_OK
;
500 #pragma mark dictionary access
503 asl_client_kvdict(asl_client_t
*client
)
505 if (client
== NULL
) return NULL
;
506 return client
->kvdict
;
510 #pragma mark asl_object support
513 _jump_dealloc(asl_object_private_t
*obj
)
515 _asl_client_free_internal((asl_client_t
*)obj
);
519 _jump_append(asl_object_private_t
*obj
, asl_object_private_t
*newobj
)
521 int type
= asl_get_type((asl_object_t
)newobj
);
523 if (type
== ASL_TYPE_LIST
)
526 asl_msg_list_reset_iteration((asl_msg_list_t
*)newobj
, 0);
527 while (NULL
!= (msg
= asl_msg_list_next((asl_msg_list_t
*)newobj
)))
529 if (asl_client_internal_send((asl_object_t
)obj
, (asl_object_t
)msg
) != ASL_STATUS_OK
) return;
532 else if ((type
== ASL_TYPE_MSG
) || (type
== ASL_TYPE_QUERY
))
534 asl_client_internal_send((asl_object_t
)obj
, (asl_object_t
)newobj
);
538 static asl_object_private_t
*
539 _jump_search(asl_object_private_t
*obj
, asl_object_private_t
*query
)
541 int type
= asl_get_type((asl_object_t
)query
);
542 if ((query
!= NULL
) && (type
!= ASL_TYPE_MSG
) && (type
!= ASL_TYPE_QUERY
)) return NULL
;
544 return (asl_object_private_t
*)asl_client_search((asl_client_t
*)obj
, (asl_msg_t
*)query
);
547 static asl_object_private_t
*
548 _jump_match(asl_object_private_t
*obj
, asl_object_private_t
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int32_t dir
)
550 asl_msg_list_t
*out
= NULL
;
551 int type
= asl_get_type((asl_object_t
)qlist
);
553 if ((qlist
!= NULL
) && (type
!= ASL_TYPE_LIST
)) return NULL
;
555 out
= asl_client_match((asl_client_t
*)obj
, (asl_msg_list_t
*)qlist
, last
, start
, count
, duration
, dir
);
556 return (asl_object_private_t
*)out
;
559 __private_extern__
const asl_jump_table_t
*
560 asl_client_jump_table()
562 static const asl_jump_table_t jump
=
565 .dealloc
= &_jump_dealloc
,
566 .set_key_val_op
= NULL
,
568 .get_val_op_for_key
= NULL
,
569 .get_key_val_op_at_index
= NULL
,
573 .get_object_at_index
= NULL
,
574 .set_iteration_index
= NULL
,
575 .remove_object_at_index
= NULL
,
576 .append
= &_jump_append
,
578 .search
= &_jump_search
,
579 .match
= &_jump_match