]> git.saurik.com Git - apple/syslog.git/blame - libsystem_asl.tproj/src/asl_client.c
syslog-267.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl_client.c
CommitLineData
f3df4c03
A
1/*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <string.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <stdarg.h>
31#include <syslog.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <time.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <libkern/OSAtomic.h>
38#include <crt_externs.h>
39#include <asl.h>
40#include <asl_private.h>
41#include <asl_ipc.h>
42#include <asl_core.h>
43#include <asl_client.h>
44
45#define PUBLIC_OPT_MASK 0x000000ff
46
47/* private asl_file SPI */
48__private_extern__ ASL_STATUS asl_file_open_write_fd(int descriptor, asl_file_t **s);
49
50/* private asl SPI */
51__private_extern__ ASL_STATUS asl_client_internal_send(asl_object_t client, asl_object_t msg);
52
53#pragma mark -
54#pragma mark asl_client_t
55
56static void
57_asl_client_free_internal(asl_client_t *client)
58{
59 uint32_t i;
60
61 if (client == NULL) return;
62
63 if (client->kvdict != NULL) asl_msg_release(client->kvdict);
64 client->kvdict = NULL;
65
66 if (client->aslfile != NULL) asl_file_close(client->aslfile);
67 client->aslfile = NULL;
68
69 for (i = 0; i < client->out_count; i++)
70 {
71 free(client->out_list[i].mfmt);
72 free(client->out_list[i].tfmt);
73 }
74
75 free(client->out_list);
76 client->out_list = NULL;
77
78 free(client);
79}
80
81asl_client_t *
82asl_client_open(const char *ident, const char *facility, uint32_t opts)
83{
84 asl_client_t *client = (asl_client_t *)calloc(1, sizeof(asl_client_t));
85 if (client == NULL)
86 {
87 errno = ENOMEM;
88 return NULL;
89 }
90
91 client->asl_type = ASL_TYPE_CLIENT;
92 client->refcount = 1;
93
94 client->kvdict = asl_msg_new(ASL_TYPE_MSG);
95 if (client->kvdict == NULL)
96 {
97 asl_client_release(client);
98 errno = ENOMEM;
99 return NULL;
100 }
101
102 client->options = opts & PUBLIC_OPT_MASK;
103
104 client->pid = getpid();
105 client->uid = getuid();
106 client->gid = getgid();
107
108 if (ident != NULL)
109 {
110 asl_msg_set_key_val(client->kvdict, ASL_KEY_SENDER, ident);
111 }
112 else
113 {
114 char *name = *(*_NSGetArgv());
115 if (name != NULL)
116 {
117 char *x = strrchr(name, '/');
118 if (x != NULL) x++;
119 else x = name;
120 asl_msg_set_key_val(client->kvdict, ASL_KEY_SENDER, x);
121 }
122 }
123
124 if (facility != NULL)
125 {
126 asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, facility);
127 }
128 else if (client->uid == 0)
129 {
130 asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, asl_syslog_faciliy_num_to_name(LOG_DAEMON));
131 }
132 else
133 {
134 asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, asl_syslog_faciliy_num_to_name(LOG_USER));
135 }
136
137 client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
138
139 if (client->options & ASL_OPT_STDERR)
140 {
141 /* only add stderr if it is valid */
142 if (fcntl(STDERR_FILENO, F_GETFD) >= 0)
143 {
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);
145 }
146 else
147 {
148 /* stderr has been closed, ignore ASL_OPT_STDERR flag */
149 client->options &= ~ASL_OPT_STDERR;
150 }
151 }
152
153 return client;
154}
155
156asl_client_t *
157asl_client_open_from_file(int descriptor, const char *ident, const char *facility)
158{
159 uint32_t status;
160 asl_client_t *client = asl_client_open(ident, facility, 0);
161 if (client == NULL) return NULL;
162
163 client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
164
165 status = asl_file_open_write_fd(descriptor, &(client->aslfile));
166 if (status != ASL_STATUS_OK)
167 {
168 _asl_client_free_internal(client);
169 return NULL;
170 }
171
172 client->aslfileid = 1;
173
174 return client;
175}
176
177asl_client_t *
178asl_client_retain(asl_client_t *client)
179{
180 if (client == NULL) return NULL;
181 asl_retain((asl_object_t)client);
182 return client;
183}
184
185void
186asl_client_release(asl_client_t *client)
187{
188 if (client == NULL) return;
189 asl_release((asl_object_t)client);
190}
191
192#pragma mark -
193#pragma mark database access
194
195ASL_STATUS
196asl_client_send(asl_client_t *client, asl_msg_t *msg)
197{
198 return asl_client_internal_send((asl_object_t)client, (asl_object_t)msg);
199}
200
201static 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)
203{
204 char *str, *res = NULL;
205 uint32_t len, reslen, status;
206 uint64_t last64, start64, count64;
207 kern_return_t kstatus;
208 asl_msg_list_t *out;
209 caddr_t vmstr;
210 mach_port_t asl_server_port = asl_core_get_service_port(0);
211
212 if (asl_server_port == MACH_PORT_NULL) return NULL;
213
214 str = NULL;
215 if (qlist == NULL)
216 {
217 asprintf(&str, "0\n");
218 len = 3;
219 }
220 else
221 {
222 str = asl_msg_list_to_string(qlist, &len);
223 }
224
225 if (str == NULL) return NULL;
226
227 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
228 if (kstatus != KERN_SUCCESS) return NULL;
229
230 memmove(vmstr, str, len);
231 free(str);
232
233 last64 = 0;
234 start64 = start;
235 count64 = count;
236
237 kstatus = _asl_server_match(asl_server_port, vmstr, len, start64, count64, duration, dir, (caddr_t *)&res, &reslen, &last64, (int *)&status);
238 *last = last64;
239
240 out = asl_msg_list_from_string(res);
241 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
242
243 return out;
244}
245
246static asl_msg_list_t *
247_do_server_search(asl_msg_t *q)
248{
249 asl_msg_list_t *out;
250 char *qstr, *str, *res = NULL;
251 uint32_t len, reslen = 0, status = ASL_STATUS_OK;
252 uint64_t cmax = 0;
253 kern_return_t kstatus;
254 caddr_t vmstr;
255 mach_port_t asl_server_port = asl_core_get_service_port(0);
256
257 if (asl_server_port == MACH_PORT_NULL) return NULL;
258
259 len = 0;
260 qstr = asl_msg_to_string(q, &len);
261
262 str = NULL;
263 if (qstr == NULL)
264 {
265 asprintf(&str, "0\n");
266 len = 3;
267 }
268 else
269 {
270 asprintf(&str, "1\n%s\n", qstr);
271 len += 3;
272 free(qstr);
273 }
274
275 if (str == NULL) return NULL;
276
277 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
278 if (kstatus != KERN_SUCCESS) return NULL;
279
280 memmove(vmstr, str, len);
281 free(str);
282
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;
285
286 out = asl_msg_list_from_string(res);
287 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
288
289 return out;
290}
291
292static 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)
294{
295 asl_msg_list_t *out;
296 uint32_t status;
297 uint64_t l64 = 0, s64;
298 asl_store_t *store = NULL;
299
300 uint32_t len;
301 char *str = asl_msg_list_to_string(qlist, &len);
302 free(str);
303
304 status = asl_store_open_read(NULL, &store);
305 if (status != 0) return NULL;
306 if (store == NULL) return NULL;
307
308 s64 = start;
309 out = asl_store_match(store, qlist, &l64, s64, count, duration, direction);
310 *last = l64;
311
312 asl_store_close(store);
313
314 return out;
315}
316
317static asl_msg_list_t *
318_do_store_search(asl_msg_t *query)
319{
320 asl_msg_list_t *out, *qlist = NULL;
321 uint32_t status;
322 uint16_t op;
323 uint64_t last = 0, start = 0;
324 asl_store_t *store = NULL;
325 const char *val = NULL;
326
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))
330 {
331 if (op & ASL_QUERY_OP_EQUAL) start = atoll(val);
332 else start = atoll(val) + 1;
333 }
334
335 status = asl_store_open_read(NULL, &store);
336 if (status != 0) return NULL;
337 if (store == NULL) return NULL;
338
339 if (query != NULL)
340 {
341 qlist = asl_msg_list_new();
342 asl_msg_list_append(qlist, query);
343 }
344
345 out = asl_store_match(store, qlist, &last, start, 0, 0, 1);
346 asl_store_close(store);
347
348 asl_msg_list_release(qlist);
349 return out;
350}
351
352asl_msg_list_t *
353asl_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)
354{
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);
357}
358
359asl_msg_list_t *
360asl_client_search(asl_client_t *client, asl_msg_t *query)
361{
362 if (asl_store_location() == ASL_STORE_LOCATION_FILE) return _do_store_search(query);
363 return _do_server_search(query);
364}
365
366
367#pragma mark -
368#pragma mark output control
369
370/* returns last filter value, or -1 on error */
371int
372asl_client_set_filter(asl_client_t *client, int filter)
373{
374 int last;
375
376 if (client == NULL) return -1;
377 last = client->filter;
378 client->filter = filter;
379 return last;
380}
381
382ASL_STATUS
383asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding)
384{
385 uint32_t i;
386
387 if (client == NULL) return ASL_STATUS_FAILED;
388
389 for (i = 0; i < client->out_count; i++)
390 {
391 if (client->out_list[i].fd == descriptor)
392 {
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);
397
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);
401
402 client->out_list[i].encoding = text_encoding;
403 client->out_list[i].filter = filter;
404
405 return ASL_STATUS_OK;
406 }
407 }
408
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));
411
412 if (client->out_list == NULL) return ASL_STATUS_FAILED;
413
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);
419
420 client->out_count++;
421
422 return ASL_STATUS_OK;
423}
424
425/* returns last filter value, or -1 on error */
426int
427asl_client_set_output_file_filter(asl_client_t *client, int descriptor, int filter)
428{
429 uint32_t i;
430 int last = 0;
431
432 if (client == NULL) return -1;
433
434 for (i = 0; i < client->out_count; i++)
435 {
436 if (client->out_list[i].fd == descriptor)
437 {
438 /* update filter */
439 last = client->out_list[i].filter;
440 client->out_list[i].filter = filter;
441 break;
442 }
443 }
444
445 return last;
446}
447
448ASL_STATUS
449asl_client_remove_output_file(asl_client_t *client, int descriptor)
450{
451 uint32_t i;
452 int x;
453
454 if (client == NULL) return ASL_STATUS_INVALID_ARG;
455
456 if (client->out_count == 0) return ASL_STATUS_OK;
457
458 x = -1;
459 for (i = 0; i < client->out_count; i++)
460 {
461 if (client->out_list[i].fd == descriptor)
462 {
463 x = i;
464 break;
465 }
466 }
467
468 if (x == -1) return ASL_STATUS_OK;
469
470 free(client->out_list[x].mfmt);
471 free(client->out_list[x].tfmt);
472
473 for (i = x + 1; i < client->out_count; i++, x++)
474 {
475 client->out_list[x] = client->out_list[i];
476 }
477
478 client->out_count--;
479
480 if (client->out_count == 0)
481 {
482 free(client->out_list);
483 client->out_list = NULL;
484 }
485 else
486 {
487 client->out_list = (asl_out_file_t *)reallocf(client->out_list, client->out_count * sizeof(asl_out_file_t));
488
489 if (client->out_list == NULL)
490 {
491 client->out_count = 0;
492 return ASL_STATUS_FAILED;
493 }
494 }
495
496 return ASL_STATUS_OK;
497}
498
499#pragma mark -
500#pragma mark dictionary access
501
502asl_msg_t *
503asl_client_kvdict(asl_client_t *client)
504{
505 if (client == NULL) return NULL;
506 return client->kvdict;
507}
508
509#pragma mark -
510#pragma mark asl_object support
511
512static void
513_jump_dealloc(asl_object_private_t *obj)
514{
515 _asl_client_free_internal((asl_client_t *)obj);
516}
517
518static void
519_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj)
520{
521 int type = asl_get_type((asl_object_t)newobj);
522
523 if (type == ASL_TYPE_LIST)
524 {
525 asl_msg_t *msg;
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)))
528 {
529 if (asl_client_internal_send((asl_object_t)obj, (asl_object_t)msg) != ASL_STATUS_OK) return;
530 }
531 }
532 else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY))
533 {
534 asl_client_internal_send((asl_object_t)obj, (asl_object_t)newobj);
535 }
536}
537
538static asl_object_private_t *
539_jump_search(asl_object_private_t *obj, asl_object_private_t *query)
540{
541 int type = asl_get_type((asl_object_t)query);
542 if ((query != NULL) && (type != ASL_TYPE_MSG) && (type != ASL_TYPE_QUERY)) return NULL;
543
544 return (asl_object_private_t *)asl_client_search((asl_client_t *)obj, (asl_msg_t *)query);
545}
546
547static 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)
549{
550 asl_msg_list_t *out = NULL;
551 int type = asl_get_type((asl_object_t)qlist);
552
553 if ((qlist != NULL) && (type != ASL_TYPE_LIST)) return NULL;
554
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;
557}
558
559__private_extern__ const asl_jump_table_t *
560asl_client_jump_table()
561{
562 static const asl_jump_table_t jump =
563 {
564 .alloc = NULL,
565 .dealloc = &_jump_dealloc,
566 .set_key_val_op = NULL,
567 .unset_key = NULL,
568 .get_val_op_for_key = NULL,
569 .get_key_val_op_at_index = NULL,
570 .count = NULL,
571 .next = NULL,
572 .prev = NULL,
573 .get_object_at_index = NULL,
574 .set_iteration_index = NULL,
575 .remove_object_at_index = NULL,
576 .append = &_jump_append,
577 .prepend = NULL,
578 .search = &_jump_search,
579 .match = &_jump_match
580 };
581
582 return &jump;
583}
584