2 * Copyright (c) 2007-2008 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@
24 #include <sys/types.h>
29 #include <sys/socket.h>
33 #include <sys/fcntl.h>
34 #include <sys/signal.h>
35 #include <sys/errno.h>
36 #include <mach/mach.h>
37 #include <mach/mach_error.h>
39 #include <netinet/in.h>
40 #include <sys/event.h>
41 #include <servers/bootstrap.h>
50 #define forever for(;;)
52 #define LIST_SIZE_DELTA 256
54 #define SEND_NOTIFICATION 0xfadefade
56 #define QUERY_FLAG_SEARCH_REVERSE 0x00000001
57 #define SEARCH_FORWARD 1
58 #define SEARCH_BACKWARD -1
60 static pthread_mutex_t db_lock
= PTHREAD_MUTEX_INITIALIZER
;
61 static pthread_mutex_t queue_lock
= PTHREAD_MUTEX_INITIALIZER
;
62 static pthread_cond_t queue_cond
= PTHREAD_COND_INITIALIZER
;
64 extern char *asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
);
65 extern asl_search_result_t
*asl_list_from_string(const char *buf
);
66 extern boolean_t
asl_ipc_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
68 static asl_search_result_t work_queue
= {0, 0, NULL
};
70 static time_t file_sweep_last
= 0;
74 mach_msg_header_t head
;
75 union __RequestUnion__asl_ipc_subsystem request
;
80 mach_msg_header_t head
;
81 union __ReplyUnion__asl_ipc_subsystem reply
;
85 list_append_msg(asl_search_result_t
*list
, asl_msg_t
*msg
, uint32_t retain
)
87 if (list
== NULL
) return;
88 if (msg
== NULL
) return;
91 * NB: curr is the list size
92 * grow list if necessary
94 if (list
->count
== list
->curr
)
98 list
->msg
= (asl_msg_t
**)calloc(LIST_SIZE_DELTA
, sizeof(asl_msg_t
*));
102 list
->msg
= (asl_msg_t
**)reallocf(list
->msg
, (list
->curr
+ LIST_SIZE_DELTA
) * sizeof(asl_msg_t
*));
105 if (list
->msg
== NULL
)
112 list
->curr
+= LIST_SIZE_DELTA
;
115 if (retain
!= 0) asl_msg_retain(msg
);
116 list
->msg
[list
->count
] = msg
;
121 db_ping_store(time_t now
)
125 if ((global
.dbtype
& DB_TYPE_FILE
) && (global
.file_db
!= NULL
))
127 delta
= now
- file_sweep_last
;
128 if (delta
>= global
.asl_store_ping_time
)
130 asl_store_sweep_file_cache(global
.file_db
);
131 file_sweep_last
= now
;
137 db_enqueue(asl_msg_t
*m
)
139 if (m
== NULL
) return;
141 pthread_mutex_lock(&queue_lock
);
142 list_append_msg(&work_queue
, m
, 1);
143 pthread_mutex_unlock(&queue_lock
);
144 pthread_cond_signal(&queue_cond
);
148 db_dequeue(uint32_t *count
)
152 pthread_mutex_lock(&queue_lock
);
153 pthread_cond_wait(&queue_cond
, &queue_lock
);
158 if (work_queue
.count
== 0)
160 pthread_mutex_unlock(&queue_lock
);
164 work
= work_queue
.msg
;
165 *count
= work_queue
.count
;
167 work_queue
.count
= 0;
169 work_queue
.msg
= NULL
;
171 pthread_mutex_unlock(&queue_lock
);
181 if ((global
.dbtype
& DB_TYPE_FILE
) && (global
.file_db
== NULL
))
183 memset(&sb
, 0, sizeof(struct stat
));
184 if (stat(PATH_ASL_STORE
, &sb
) == 0)
186 /* must be a directory */
187 if ((sb
.st_mode
& S_IFDIR
) == 0)
189 asldebug("error: %s is not a directory", PATH_ASL_STORE
);
197 /* /var/log/asl doesn't exist - create it */
198 if (mkdir(PATH_ASL_STORE
, 0755) != 0)
200 asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
206 /* stat failed for some other reason */
207 asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
212 status
= asl_store_open_write(NULL
, &(global
.file_db
));
213 if (status
!= ASL_STATUS_OK
)
215 asldebug("asl_store_open_write: %s\n", asl_core_error(status
));
219 if (global
.db_file_max
!= 0) asl_store_max_file_size(global
.file_db
, global
.db_file_max
);
222 if (global
.did_store_sweep
== 0)
224 status
= asl_store_signal_sweep(global
.file_db
);
225 if (status
== ASL_STATUS_OK
) global
.did_store_sweep
= 1;
229 if ((global
.dbtype
& DB_TYPE_MEMORY
) && (global
.memory_db
== NULL
))
231 status
= asl_memory_open(global
.db_memory_max
, &(global
.memory_db
));
232 if (status
!= ASL_STATUS_OK
)
234 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
238 if ((global
.dbtype
& DB_TYPE_MINI
) && (global
.mini_db
== NULL
))
240 status
= asl_mini_memory_open(global
.db_mini_max
, &(global
.mini_db
));
241 if (status
!= ASL_STATUS_OK
)
243 asldebug("asl_mini_memory_open: %s\n", asl_core_error(status
));
249 * Takes messages off the work queue and saves them in the database.
250 * Runs in it's own thread.
257 uint32_t i
, count
, status
;
258 mach_msg_empty_send_t
*msg
;
259 kern_return_t kstatus
;
261 msg
= (mach_msg_empty_send_t
*)calloc(1, sizeof(mach_msg_empty_send_t
));
262 if (msg
== NULL
) return;
264 msg
->header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSGH_BITS_ZERO
);
265 msg
->header
.msgh_remote_port
= global
.server_port
;
266 msg
->header
.msgh_local_port
= MACH_PORT_NULL
;
267 msg
->header
.msgh_size
= sizeof(mach_msg_empty_send_t
);
268 msg
->header
.msgh_id
= SEND_NOTIFICATION
;
273 work
= db_dequeue(&count
);
275 if (work
== NULL
) continue;
277 pthread_mutex_lock(&db_lock
);
281 for (i
= 0; i
< count
; i
++)
283 if (global
.dbtype
& DB_TYPE_FILE
)
285 status
= asl_store_save(global
.file_db
, work
[i
]);
286 if (status
!= ASL_STATUS_OK
)
288 /* write failed - reopen & retry */
289 asldebug("asl_store_save: %s\n", asl_core_error(status
));
290 asl_store_close(global
.file_db
);
291 global
.file_db
= NULL
;
294 status
= asl_store_save(global
.file_db
, work
[i
]);
295 if (status
!= ASL_STATUS_OK
)
297 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status
));
298 asl_store_close(global
.file_db
);
299 global
.file_db
= NULL
;
301 global
.dbtype
|= DB_TYPE_MEMORY
;
302 if (global
.memory_db
== NULL
)
304 status
= asl_memory_open(global
.db_memory_max
, &(global
.memory_db
));
305 if (status
!= ASL_STATUS_OK
)
307 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
314 if (global
.dbtype
& DB_TYPE_MEMORY
)
317 status
= asl_memory_save(global
.memory_db
, work
[i
], &msgid
);
318 if (status
!= ASL_STATUS_OK
)
320 /* save failed - reopen & retry*/
321 asldebug("asl_memory_save: %s\n", asl_core_error(status
));
322 asl_memory_close(global
.memory_db
);
323 global
.memory_db
= NULL
;
327 status
= asl_memory_save(global
.memory_db
, work
[i
], &msgid
);
328 if (status
!= ASL_STATUS_OK
)
330 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status
));
331 asl_memory_close(global
.memory_db
);
332 global
.memory_db
= NULL
;
337 if (global
.dbtype
& DB_TYPE_MINI
)
339 status
= asl_mini_memory_save(global
.mini_db
, work
[i
], &msgid
);
340 if (status
!= ASL_STATUS_OK
)
342 /* save failed - reopen & retry*/
343 asldebug("asl_mini_memory_save: %s\n", asl_core_error(status
));
344 asl_mini_memory_close(global
.mini_db
);
345 global
.mini_db
= NULL
;
348 status
= asl_mini_memory_save(global
.mini_db
, work
[i
], &msgid
);
349 if (status
!= ASL_STATUS_OK
)
351 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status
));
352 asl_mini_memory_close(global
.mini_db
);
353 global
.mini_db
= NULL
;
358 if ((i
% 500) == 499)
360 pthread_mutex_unlock(&db_lock
);
361 pthread_mutex_lock(&db_lock
);
365 pthread_mutex_unlock(&db_lock
);
367 for (i
= 0; i
< count
; i
++) asl_msg_release(work
[i
]);
370 kstatus
= mach_msg(&(msg
->header
), MACH_SEND_MSG
, msg
->header
.msgh_size
, 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
375 disaster_message(asl_msg_t
*msg
)
382 if ((global
.dbtype
& DB_TYPE_MINI
) == 0)
384 if (global
.mini_db
== NULL
)
386 status
= asl_mini_memory_open(global
.db_mini_max
, &(global
.mini_db
));
387 if (status
!= ASL_STATUS_OK
) asldebug("asl_mini_memory_open: %s\n", asl_core_error(status
));
388 else asl_mini_memory_save(global
.mini_db
, msg
, &msgid
);
394 * Do a database search.
397 db_query(aslresponse query
, aslresponse
*res
, uint64_t startid
, int count
, int flags
, uint64_t *lastid
, int32_t ruid
, int32_t rgid
)
399 uint32_t status
, ucount
;
403 dir
= SEARCH_FORWARD
;
404 if (flags
& QUERY_FLAG_SEARCH_REVERSE
) dir
= SEARCH_BACKWARD
;
406 pthread_mutex_lock(&db_lock
);
408 status
= ASL_STATUS_FAILED
;
410 if (global
.dbtype
& DB_TYPE_MEMORY
) status
= asl_memory_match(global
.memory_db
, query
, res
, lastid
, startid
, ucount
, dir
, ruid
, rgid
);
411 else status
= asl_mini_memory_match(global
.mini_db
, query
, res
, lastid
, startid
, ucount
, dir
);
413 pthread_mutex_unlock(&db_lock
);
419 * Receives messages on the "com.apple.system.logger" mach port.
420 * Services database search requests.
421 * Runs in it's own thread.
426 kern_return_t kstatus
;
427 asl_request_msg
*request
;
428 asl_reply_msg
*reply
;
430 uint32_t rbits
, sbits
;
431 uint32_t flags
, snooze
;
432 struct timeval now
, send_time
;
434 send_time
.tv_sec
= 0;
435 send_time
.tv_usec
= 0;
437 rqs
= sizeof(asl_request_msg
) + MAX_TRAILER_SIZE
;
438 rps
= sizeof(asl_reply_msg
) + MAX_TRAILER_SIZE
;
439 reply
= (asl_reply_msg
*)calloc(1, rps
);
440 if (reply
== NULL
) return;
442 rbits
= MACH_RCV_MSG
| MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
);
443 sbits
= MACH_SEND_MSG
| MACH_SEND_TIMEOUT
;
451 /* Check if it's time to post a database change notification */
452 if (send_time
.tv_sec
!= 0)
454 gettimeofday(&now
, NULL
);
455 if ((now
.tv_sec
> send_time
.tv_sec
) || ((now
.tv_sec
== send_time
.tv_sec
) && (now
.tv_usec
> send_time
.tv_usec
)))
457 notify_post(ASL_DB_NOTIFICATION
);
458 notify_post(SELF_DB_NOTIFICATION
);
459 send_time
.tv_sec
= 0;
460 send_time
.tv_usec
= 0;
465 /* mach_msg timeout is in milliseconds */
466 snooze
= ((send_time
.tv_sec
- now
.tv_sec
) * 1000) + ((send_time
.tv_usec
- now
.tv_usec
) / 1000);
470 request
= (asl_request_msg
*)calloc(1, rqs
);
471 if (request
== NULL
) continue;
473 request
->head
.msgh_local_port
= global
.server_port
;
474 request
->head
.msgh_size
= rqs
;
476 memset(reply
, 0, rps
);
479 if (snooze
!= 0) flags
|= MACH_RCV_TIMEOUT
;
481 kstatus
= mach_msg(&(request
->head
), flags
, 0, rqs
, global
.server_port
, snooze
, MACH_PORT_NULL
);
482 if (request
->head
.msgh_id
== SEND_NOTIFICATION
)
484 if (send_time
.tv_sec
== 0)
486 gettimeofday(&send_time
, NULL
);
487 send_time
.tv_sec
+= 1;
494 kstatus
= asl_ipc_server(&(request
->head
), &(reply
->head
));
495 kstatus
= mach_msg(&(reply
->head
), sbits
, reply
->head
.msgh_size
, 0, MACH_PORT_NULL
, 10, MACH_PORT_NULL
);
496 if (kstatus
== MACH_SEND_INVALID_DEST
)
498 mach_port_destroy(mach_task_self(), request
->head
.msgh_remote_port
);
510 mach_msg_type_number_t requestCnt
,
515 mach_msg_type_number_t
*replyCnt
,
518 security_token_t
*token
523 char *out
, *vmbuffer
;
525 kern_return_t kstatus
;
527 *status
= ASL_STATUS_OK
;
528 query
= asl_list_from_string(request
);
529 vm_deallocate(mach_task_self(), (vm_address_t
)request
, requestCnt
);
532 *status
= db_query(query
, &res
, startid
, count
, flags
, lastid
, token
->val
[0], token
->val
[1]);
534 aslresponse_free(query
);
535 if (*status
!= ASL_STATUS_OK
)
537 if (res
!= NULL
) aslresponse_free(res
);
543 out
= asl_list_to_string((asl_search_result_t
*)res
, &outlen
);
544 aslresponse_free(res
);
546 if ((out
== NULL
) || (outlen
== 0)) return KERN_SUCCESS
;
548 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmbuffer
, outlen
, TRUE
);
549 if (kstatus
!= KERN_SUCCESS
)
555 memmove(vmbuffer
, out
, outlen
);
566 __asl_server_query_timeout
570 mach_msg_type_number_t requestCnt
,
575 mach_msg_type_number_t
*replyCnt
,
578 security_token_t
*token
581 return __asl_server_query(server
, request
, requestCnt
, startid
, count
, flags
, reply
, replyCnt
, lastid
, status
, token
);
589 mach_msg_type_number_t requestCnt
,
591 security_token_t
*token