]> git.saurik.com Git - apple/syslog.git/blame - aslcommon/asl_mini_memory.c
syslog-132.tar.gz
[apple/syslog.git] / aslcommon / asl_mini_memory.c
CommitLineData
57b0aad2 1/*
a83ff38a 2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
57b0aad2
A
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 <asl_core.h>
a83ff38a
A
25#include "asl_mini_memory.h"
26#include <unistd.h>x
57b0aad2
A
27#include <stdlib.h>
28#include <stdio.h>
29#include <sys/errno.h>
30#include <string.h>
31#include <sys/types.h>
32#include <time.h>
33#include <asl_private.h>
a83ff38a 34#include <asl_msg.h>
57b0aad2
A
35
36#define DEFAULT_MAX_RECORDS 256
37#define MEM_STRING_HEADER_SIZE 8
38#define CFLOG_LOCAL_TIME_KEY "CFLog Local Time"
39#define CFLOG_THREAD_KEY "CFLog Thread"
40
41#define forever for(;;)
42extern time_t asl_parse_time(const char *str);
43extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
44
45uint32_t
46asl_mini_memory_statistics(asl_mini_memory_t *s, aslmsg *msg)
47{
48 aslmsg out;
49 uint32_t i, n;
50 uint64_t size;
51 char str[256];
52
53 if (s == NULL) return ASL_STATUS_INVALID_STORE;
54 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
55
a83ff38a 56 out = asl_new(ASL_TYPE_MSG);
57b0aad2
A
57 if (out == NULL) return ASL_STATUS_NO_MEMORY;
58
59 size = sizeof(asl_mini_memory_t);
60 size += ((s->record_count + 1) * sizeof(mini_mem_record_t));
61
62 for (i = 0; i < s->string_count; i++)
63 {
64 size += MEM_STRING_HEADER_SIZE;
65 if (((mini_mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mini_mem_string_t *)s->string_cache[i])->str) + 1);
66 }
67
68 snprintf(str, sizeof(str), "%llu", size);
69 asl_set(out, "Size", str);
70
71 n = 0;
72 for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++;
73
74 snprintf(str, sizeof(str), "%u", n);
75 asl_set(out, "RecordCount", str);
76
77 snprintf(str, sizeof(str), "%u", s->string_count);
78 asl_set(out, "StringCount", str);
79
80 *msg = out;
81 return ASL_STATUS_OK;
82}
83
84uint32_t
85asl_mini_memory_close(asl_mini_memory_t *s)
86{
87 uint32_t i;
88
89 if (s == NULL) return ASL_STATUS_OK;
90
91 if (s->record != NULL)
92 {
93 for (i = 0; i < s->record_count; i++)
94 {
95 if (s->record[i] != NULL) free(s->record[i]);
96 s->record[i] = NULL;
97 }
98
99 free(s->record);
100 s->record = NULL;
101 }
102
103 if (s->buffer_record != NULL) free(s->buffer_record);
104
105 if (s->string_cache != NULL)
106 {
107 for (i = 0; i < s->string_count; i++)
108 {
109 if (s->string_cache[i] != NULL) free(s->string_cache[i]);
110 s->string_cache[i] = NULL;
111 }
112
113 free(s->string_cache);
114 s->string_cache = NULL;
115 }
116
117 free(s);
118
119 return ASL_STATUS_OK;
120}
121
122uint32_t
123asl_mini_memory_open(uint32_t max_records, asl_mini_memory_t **s)
124{
125 asl_mini_memory_t *out;
126 uint32_t i;
127
128 if (s == NULL) return ASL_STATUS_INVALID_ARG;
129
130 if (max_records == 0) max_records = DEFAULT_MAX_RECORDS;
131
132 out = calloc(1, sizeof(asl_mini_memory_t));
133 if (out == NULL) return ASL_STATUS_NO_MEMORY;
134
135 out->record_count = max_records;
136 out->record = (mini_mem_record_t **)calloc(max_records, sizeof(mini_mem_record_t *));
137 if (out->record == NULL)
138 {
139 free(out);
140 return ASL_STATUS_NO_MEMORY;
141 }
142
143 for (i = 0; i < max_records; i++)
144 {
145 out->record[i] = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t));
146 if (out->record[i] == NULL)
147 {
148 asl_mini_memory_close(out);
149 return ASL_STATUS_NO_MEMORY;
150 }
151 }
152
153 out->buffer_record = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t));
154 if (out->buffer_record == NULL)
155 {
156 asl_mini_memory_close(out);
157 return ASL_STATUS_NO_MEMORY;
158 }
159
160 out->next_id = 1;
161
162 *s = out;
163 return ASL_STATUS_OK;
164}
165
166static mini_mem_string_t *
167mem_string_new(const char *str, uint32_t len, uint32_t hash)
168{
169 mini_mem_string_t *out;
170 size_t ss;
171
172 if (str == NULL) return NULL;
173
174 ss = MEM_STRING_HEADER_SIZE + len + 1;
175 out = (mini_mem_string_t *)calloc(1, ss);
176 if (out == NULL) return NULL;
177
178 out->hash = hash;
179 out->refcount = 1;
180 memcpy(out->str, str, len);
181
182 return out;
183}
184
185/*
186 * Find the first hash greater than or equal to a given hash in the string cache.
187 * Return s->string_count if hash is greater that or equal to last hash in the string cache.
188 * Caller must check if the hashes match or not.
189 *
190 * This routine is used both to find strings in the cache and to determine where to insert
191 * new strings. Note that the caller needs to do extra work after calling this routine.
192 */
193static uint32_t
194asl_mini_memory_string_cache_search_hash(asl_mini_memory_t *s, uint32_t hash)
195{
196 uint32_t top, bot, mid, range;
197 mini_mem_string_t *ms;
198
199 if (s->string_count == 0) return 0;
200 if (s->string_count == 1)
201 {
202 ms = (mini_mem_string_t *)s->string_cache[0];
203 if (hash < ms->hash) return 0;
204 return 1;
205 }
206
207 top = s->string_count - 1;
208 bot = 0;
209 mid = top / 2;
210
211 range = top - bot;
212 while (range > 1)
213 {
214 ms = (mini_mem_string_t *)s->string_cache[mid];
215
216 if (hash == ms->hash)
217 {
218 while (mid > 0)
219 {
220 ms = (mini_mem_string_t *)s->string_cache[mid - 1];
221 if (hash != ms->hash) break;
222 mid--;
223 }
224
225 return mid;
226 }
227 else
228 {
229 ms = (mini_mem_string_t *)s->string_cache[mid];
230 if (hash < ms->hash) top = mid;
231 else bot = mid;
232 }
233
234 range = top - bot;
235 mid = bot + (range / 2);
236 }
237
238 ms = (mini_mem_string_t *)s->string_cache[bot];
239 if (hash <= ms->hash) return bot;
240
241 ms = (mini_mem_string_t *)s->string_cache[top];
242 if (hash <= ms->hash) return top;
243
244 return s->string_count;
245}
246
247/*
248 * Search the string cache.
249 * If the string is in the cache, increment refcount and return it.
250 * If the string is not in cache and create flag is on, create a new string.
251 * Otherwise, return NULL.
252 */
253static mini_mem_string_t *
254asl_mini_memory_string_retain(asl_mini_memory_t *s, const char *str, int create)
255{
256 uint32_t i, where, hash, len;
257
258 if (s == NULL) return NULL;
259 if (str == NULL) return NULL;
260 len = strlen(str);
261
262 /* check the cache */
263 hash = asl_core_string_hash(str, len);
264 where = asl_mini_memory_string_cache_search_hash(s, hash);
265
266 /* asl_mini_memory_string_cache_search_hash just tells us where to look */
267 if (where < s->string_count)
268 {
269 while (((mini_mem_string_t *)(s->string_cache[where]))->hash == hash)
270 {
271 if (!strcmp(str, ((mini_mem_string_t *)(s->string_cache[where]))->str))
272 {
273 ((mini_mem_string_t *)(s->string_cache[where]))->refcount++;
274 return s->string_cache[where];
275 }
276
277 where++;
278 }
279 }
280
281 /* not found */
282 if (create == 0) return NULL;
283
284 /* create a new mini_mem_string_t and insert into the cache at index 'where' */
285 if (s->string_count == 0)
286 {
287 s->string_cache = (void **)calloc(1, sizeof(void *));
288 }
289 else
290 {
291 s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
292 for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
293 }
294
295 if (s->string_cache == NULL)
296 {
297 s->string_count = 0;
298 return NULL;
299 }
300
301 s->string_count++;
302 s->string_cache[where] = mem_string_new(str, len, hash);
303
304 return s->string_cache[where];
305}
306
307static uint32_t
308asl_mini_memory_string_release(asl_mini_memory_t *s, mini_mem_string_t *m)
309{
310 uint32_t i, where;
311
312 if (s == NULL) return ASL_STATUS_INVALID_STORE;
313 if (m == NULL) return ASL_STATUS_OK;
314
315 if (m->refcount > 0) m->refcount--;
316 if (m->refcount > 0) return ASL_STATUS_OK;
317
318 where = asl_mini_memory_string_cache_search_hash(s, m->hash);
319 if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
320
321 while (s->string_cache[where] != m)
322 {
323 if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
324
325 where++;
326 if (where >= s->string_count) return ASL_STATUS_OK;
327 }
328
329 for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
330
331 free(m);
332 s->string_count--;
333
334 if (s->string_count == 0)
335 {
336 free(s->string_cache);
337 s->string_cache = NULL;
338 return ASL_STATUS_OK;
339 }
340
341 s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *));
342 if (s->string_cache == NULL)
343 {
344 s->string_count = 0;
345 return ASL_STATUS_NO_MEMORY;
346 }
347
348 return ASL_STATUS_OK;
349}
350
351/*
352 * Release all a record's strings and reset it's values
353 */
354static void
355asl_mini_memory_record_clear(asl_mini_memory_t *s, mini_mem_record_t *r)
356{
357 uint32_t i;
358
359 if (s == NULL) return;
360 if (r == NULL) return;
361
362 asl_mini_memory_string_release(s, r->sender);
363 asl_mini_memory_string_release(s, r->facility);
364 asl_mini_memory_string_release(s, r->message);
365
366 for (i = 0; i < r->kvcount; i++) asl_mini_memory_string_release(s, r->kvlist[i]);
367
368 if (r->kvlist != NULL) free(r->kvlist);
369 memset(r, 0, sizeof(mini_mem_record_t));
370}
371
372static void
373asl_mini_memory_record_free(asl_mini_memory_t *s, mini_mem_record_t *r)
374{
375 asl_mini_memory_record_clear(s, r);
376 free(r);
377}
378
379/*
380 * Encode an aslmsg as a record structure.
381 * Creates and caches strings.
382 */
383static uint32_t
a83ff38a 384asl_mini_memory_message_encode(asl_mini_memory_t *s, aslmsg msg)
57b0aad2 385{
a83ff38a 386 uint32_t x;
57b0aad2 387 mini_mem_string_t *k, *v;
a83ff38a
A
388 mini_mem_record_t *r;
389 const char *key, *val;
57b0aad2
A
390
391 if (s == NULL) return ASL_STATUS_INVALID_STORE;
a83ff38a 392 if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
57b0aad2 393 if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE;
a83ff38a
A
394
395 r = s->buffer_record;
57b0aad2
A
396
397 memset(r, 0, sizeof(mini_mem_record_t));
398
399 r->flags = 0;
400 r->level = ASL_LEVEL_DEBUG;
401 r->pid = -1;
402 r->time = (uint64_t)-1;
403
a83ff38a
A
404 key = NULL;
405 val = NULL;
406
407 for (x = asl_msg_fetch((asl_msg_t *)msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)msg, x, &key, &val, NULL))
57b0aad2 408 {
a83ff38a 409 if (key == NULL) continue;
57b0aad2 410
a83ff38a 411 else if (!strcmp(key, ASL_KEY_TIME))
57b0aad2 412 {
a83ff38a 413 if (val != NULL) r->time = asl_parse_time(val);
57b0aad2 414 }
a83ff38a 415 else if (!strcmp(key, ASL_KEY_SENDER))
57b0aad2 416 {
a83ff38a 417 if (val != NULL) r->sender = asl_mini_memory_string_retain(s, val, 1);
57b0aad2 418 }
a83ff38a 419 else if (!strcmp(key, ASL_KEY_PID))
57b0aad2 420 {
a83ff38a 421 if (val != NULL) r->pid = atoi(val);
57b0aad2 422 }
a83ff38a 423 else if (!strcmp(key, ASL_KEY_LEVEL))
57b0aad2 424 {
a83ff38a 425 if (val != NULL) r->level = atoi(val);
57b0aad2 426 }
a83ff38a 427 else if (!strcmp(key, ASL_KEY_MSG))
57b0aad2 428 {
a83ff38a 429 if (val != NULL) r->message = asl_mini_memory_string_retain(s, val, 1);
57b0aad2 430 }
a83ff38a 431 else if (!strcmp(key, ASL_KEY_FACILITY))
57b0aad2 432 {
a83ff38a 433 if (val != NULL) r->facility = asl_mini_memory_string_retain(s, val, 1);
57b0aad2 434 }
a83ff38a 435 else if (!strcmp(key, ASL_KEY_MSG_ID))
57b0aad2
A
436 {
437 /* Ignore */
438 continue;
439 }
a83ff38a 440 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
57b0aad2
A
441 {
442 /* Ignore */
443 continue;
444 }
a83ff38a 445 else if (!strcmp(key, ASL_KEY_HOST))
57b0aad2
A
446 {
447 /* Ignore */
448 continue;
449 }
a83ff38a 450 else if (!strcmp(key, ASL_KEY_REF_PID))
57b0aad2
A
451 {
452 /* Ignore */
453 continue;
454 }
a83ff38a 455 else if (!strcmp(key, ASL_KEY_REF_PROC))
57b0aad2
A
456 {
457 /* Ignore */
458 continue;
459 }
a83ff38a 460 else if (!strcmp(key, ASL_KEY_SESSION))
57b0aad2
A
461 {
462 /* Ignore */
463 continue;
464 }
a83ff38a 465 else if (!strcmp(key, ASL_KEY_UID))
57b0aad2
A
466 {
467 /* Ignore */
468 continue;
469 }
a83ff38a 470 else if (!strcmp(key, ASL_KEY_GID))
57b0aad2
A
471 {
472 /* Ignore */
473 continue;
474 }
a83ff38a 475 else if (!strcmp(key, ASL_KEY_READ_UID))
57b0aad2
A
476 {
477 /* Ignore */
478 continue;
479 }
a83ff38a 480 else if (!strcmp(key, ASL_KEY_READ_GID))
57b0aad2
A
481 {
482 /* Ignore */
483 continue;
484 }
a83ff38a 485 else if (!strcmp(key, CFLOG_LOCAL_TIME_KEY))
57b0aad2
A
486 {
487 /* Ignore */
488 continue;
489 }
a83ff38a 490 else if (!strcmp(key, CFLOG_THREAD_KEY))
57b0aad2
A
491 {
492 /* Ignore */
493 continue;
494 }
495 else
496 {
a83ff38a 497 k = asl_mini_memory_string_retain(s, key, 1);
57b0aad2
A
498 if (k == NULL) continue;
499
500 v = NULL;
a83ff38a 501 if (val != NULL) v = asl_mini_memory_string_retain(s, val, 1);
57b0aad2
A
502
503 if (r->kvcount == 0)
504 {
505 r->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *));
506 }
507 else
508 {
509 r->kvlist = (mini_mem_string_t **)realloc(r->kvlist, (r->kvcount + 2) * sizeof(mini_mem_string_t *));
510 }
511
512 if (r->kvlist == NULL)
513 {
514 asl_mini_memory_record_clear(s, r);
515 return ASL_STATUS_NO_MEMORY;
516 }
517
518 r->kvlist[r->kvcount++] = k;
519 r->kvlist[r->kvcount++] = v;
520 }
521 }
522
523 return ASL_STATUS_OK;
524}
525
526uint32_t
527asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid)
528{
529 uint32_t status;
530 mini_mem_record_t *t;
531
532 if (s == NULL) return ASL_STATUS_INVALID_STORE;
533 if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
534
535 /* asl_mini_memory_message_encode creates and caches strings */
a83ff38a 536 status = asl_mini_memory_message_encode(s, msg);
57b0aad2
A
537 if (status != ASL_STATUS_OK) return status;
538
539 s->buffer_record->mid = s->next_id;
540 s->next_id++;
541
542 /* clear the first record */
543 t = s->record[s->record_first];
544 asl_mini_memory_record_clear(s, t);
545
546 /* add the new record to the record list (swap in the buffer record) */
547 s->record[s->record_first] = s->buffer_record;
548 s->buffer_record = t;
549
550 /* record list is a circular queue */
551 s->record_first++;
552 if (s->record_first >= s->record_count) s->record_first = 0;
553
554 *mid = s->buffer_record->mid;
555
556 return status;
557}
558
559/*
560 * Decodes a record structure.
561 */
562static uint32_t
a83ff38a 563asl_mini_memory_message_decode(asl_mini_memory_t *s, mini_mem_record_t *r, aslmsg *out)
57b0aad2 564{
a83ff38a
A
565 uint32_t i;
566 aslmsg msg;
567 char tmp[64];
568 const char *key, *val;
57b0aad2
A
569
570 if (s == NULL) return ASL_STATUS_INVALID_STORE;
571 if (r == NULL) return ASL_STATUS_INVALID_ARG;
572 if (out == NULL) return ASL_STATUS_INVALID_ARG;
573
574 *out = NULL;
575
a83ff38a 576 msg = asl_new(ASL_TYPE_MSG);
57b0aad2
A
577 if (msg == NULL) return ASL_STATUS_NO_MEMORY;
578
57b0aad2 579 /* Message ID */
a83ff38a
A
580 snprintf(tmp, sizeof(tmp), "%u", r->mid);
581 asl_set(msg, ASL_KEY_MSG_ID, tmp);
57b0aad2
A
582
583 /* Level */
a83ff38a
A
584 snprintf(tmp, sizeof(tmp), "%u", r->level);
585 asl_set(msg, ASL_KEY_LEVEL, tmp);
57b0aad2
A
586
587 /* Time */
588 if (r->time != (uint64_t)-1)
589 {
a83ff38a
A
590 snprintf(tmp, sizeof(tmp), "%llu", r->time);
591 asl_set(msg, ASL_KEY_TIME, tmp);
57b0aad2
A
592 }
593
594 /* Sender */
595 if (r->sender != NULL)
596 {
a83ff38a 597 asl_set(msg, ASL_KEY_SENDER, r->sender->str);
57b0aad2
A
598 }
599
600 /* Facility */
601 if (r->facility != NULL)
602 {
a83ff38a 603 asl_set(msg, ASL_KEY_FACILITY, r->facility->str);
57b0aad2
A
604 }
605
606 /* PID */
607 if (r->pid != -1)
608 {
a83ff38a
A
609 snprintf(tmp, sizeof(tmp), "%d", r->pid);
610 asl_set(msg, ASL_KEY_PID, tmp);
57b0aad2
A
611 }
612
613 /* Message */
614 if (r->message != NULL)
615 {
a83ff38a 616 asl_set(msg, ASL_KEY_MSG, r->message->str);
57b0aad2
A
617 }
618
619 /* Key - Value List */
620 for (i = 0; i < r->kvcount; i++)
621 {
a83ff38a
A
622 key = NULL;
623 val = NULL;
624
625 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str;
57b0aad2 626 i++;
a83ff38a
A
627 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str;
628
629 if (key != NULL) asl_set(msg, key, val);
57b0aad2
A
630 }
631
632 *out = msg;
633 return ASL_STATUS_OK;
634}
635
636uint32_t
637asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg)
638{
639 uint32_t i;
640
641 if (s == NULL) return ASL_STATUS_INVALID_STORE;
642 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
643
644 for (i = 0; i < s->record_count; i++)
645 {
646 if (s->record[i]->mid == 0) break;
647 if (s->record[i]->mid == mid) return asl_mini_memory_message_decode(s, s->record[i], msg);
648 }
649
650 return ASL_STATUS_INVALID_ID;
651}
652
653static mini_mem_record_t *
654asl_mini_memory_query_to_record(asl_mini_memory_t *s, asl_msg_t *q, uint32_t *type)
655{
656 mini_mem_record_t *out;
a83ff38a
A
657 uint32_t i, x, op;
658 mini_mem_string_t *mkey, *mval;
659 const char *key, *val;
57b0aad2
A
660
661 if (type == NULL) return NULL;
662
663 if (s == NULL)
664 {
665 *type = ASL_QUERY_MATCH_ERROR;
666 return NULL;
667 }
668
669 /* NULL query matches anything */
670 *type = ASL_QUERY_MATCH_TRUE;
671 if (q == NULL) return NULL;
a83ff38a 672 if (asl_msg_count((asl_msg_t *)q) == 0) return NULL;
57b0aad2
A
673
674
675 /* we can only do fast match on equality tests */
676 *type = ASL_QUERY_MATCH_SLOW;
a83ff38a
A
677
678 for (x = asl_msg_fetch((asl_msg_t *)q, 0, NULL, NULL, &op); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)q, x, NULL, NULL, &op))
57b0aad2 679 {
a83ff38a 680 if (op != ASL_QUERY_OP_EQUAL) return NULL;
57b0aad2
A
681 }
682
683 out = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t));
684 if (out == NULL)
685 {
686 *type = ASL_QUERY_MATCH_ERROR;
687 return NULL;
688 }
689
a83ff38a 690 for (x = asl_msg_fetch((asl_msg_t *)q, 0, &key, &val, &op); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)q, x, &key, &val, &op))
57b0aad2 691 {
a83ff38a 692 if (key == NULL) continue;
57b0aad2 693
a83ff38a 694 else if (!strcmp(key, ASL_KEY_MSG_ID))
57b0aad2 695 {
a83ff38a 696 if (val == NULL) continue;
57b0aad2
A
697
698 if (*type & ASL_QUERY_MATCH_MSG_ID)
699 {
700 asl_mini_memory_record_free(s, out);
701 *type = ASL_QUERY_MATCH_SLOW;
702 return NULL;
703 }
704
705 *type |= ASL_QUERY_MATCH_MSG_ID;
a83ff38a 706 out->mid = atoll(val);
57b0aad2 707 }
a83ff38a 708 else if (!strcmp(key, ASL_KEY_TIME))
57b0aad2 709 {
a83ff38a 710 if (val == NULL) continue;
57b0aad2
A
711
712 if (*type & ASL_QUERY_MATCH_TIME)
713 {
714 asl_mini_memory_record_free(s, out);
715 *type = ASL_QUERY_MATCH_SLOW;
716 return NULL;
717 }
718
719 *type |= ASL_QUERY_MATCH_TIME;
a83ff38a 720 out->time = asl_parse_time(val);
57b0aad2 721 }
a83ff38a 722 else if (!strcmp(key, ASL_KEY_LEVEL))
57b0aad2 723 {
a83ff38a 724 if (val == NULL) continue;
57b0aad2
A
725
726 if (*type & ASL_QUERY_MATCH_LEVEL)
727 {
728 asl_mini_memory_record_free(s, out);
729 *type = ASL_QUERY_MATCH_SLOW;
730 return NULL;
731 }
732
733 *type |= ASL_QUERY_MATCH_LEVEL;
a83ff38a 734 out->level = atoi(val);
57b0aad2 735 }
a83ff38a 736 else if (!strcmp(key, ASL_KEY_PID))
57b0aad2 737 {
a83ff38a 738 if (val == NULL) continue;
57b0aad2
A
739
740 if (*type & ASL_QUERY_MATCH_PID)
741 {
742 asl_mini_memory_record_free(s, out);
743 *type = ASL_QUERY_MATCH_SLOW;
744 return NULL;
745 }
746
747 *type |= ASL_QUERY_MATCH_PID;
a83ff38a 748 out->pid = atoi(val);
57b0aad2 749 }
a83ff38a 750 else if (!strcmp(key, ASL_KEY_SENDER))
57b0aad2 751 {
a83ff38a 752 if (val == NULL) continue;
57b0aad2
A
753
754 if (*type & ASL_QUERY_MATCH_SENDER)
755 {
756 asl_mini_memory_record_free(s, out);
757 *type = ASL_QUERY_MATCH_SLOW;
758 return NULL;
759 }
760
761 *type |= ASL_QUERY_MATCH_SENDER;
a83ff38a 762 out->sender = asl_mini_memory_string_retain(s, val, 0);
57b0aad2
A
763 if (out->sender == NULL)
764 {
765 asl_mini_memory_record_free(s, out);
766 *type = ASL_QUERY_MATCH_FALSE;
767 return NULL;
768 }
769 }
a83ff38a 770 else if (!strcmp(key, ASL_KEY_FACILITY))
57b0aad2 771 {
a83ff38a 772 if (val == NULL) continue;
57b0aad2
A
773
774 if (*type & ASL_QUERY_MATCH_FACILITY)
775 {
776 asl_mini_memory_record_free(s, out);
777 *type = ASL_QUERY_MATCH_SLOW;
778 return NULL;
779 }
780
781 *type |= ASL_QUERY_MATCH_FACILITY;
a83ff38a 782 out->facility = asl_mini_memory_string_retain(s, val, 0);
57b0aad2
A
783 if (out->facility == NULL)
784 {
785 asl_mini_memory_record_free(s, out);
786 *type = ASL_QUERY_MATCH_FALSE;
787 return NULL;
788 }
789 }
a83ff38a 790 else if (!strcmp(key, ASL_KEY_MSG))
57b0aad2 791 {
a83ff38a 792 if (val == NULL) continue;
57b0aad2
A
793
794 if (*type & ASL_QUERY_MATCH_MESSAGE)
795 {
796 asl_mini_memory_record_free(s, out);
797 *type = ASL_QUERY_MATCH_SLOW;
798 return NULL;
799 }
800
801 *type |= ASL_QUERY_MATCH_MESSAGE;
a83ff38a 802 out->message = asl_mini_memory_string_retain(s, val, 0);
57b0aad2
A
803 if (out->message == NULL)
804 {
805 asl_mini_memory_record_free(s, out);
806 *type = ASL_QUERY_MATCH_FALSE;
807 return NULL;
808 }
809 }
810 else
811 {
a83ff38a
A
812 mkey = asl_mini_memory_string_retain(s, key, 0);
813 if (mkey == NULL)
57b0aad2
A
814 {
815 asl_mini_memory_record_free(s, out);
816 *type = ASL_QUERY_MATCH_FALSE;
817 return NULL;
818 }
819
a83ff38a 820 for (i = 0; i < out->kvcount; i += 2)
57b0aad2 821 {
a83ff38a 822 if (out->kvlist[i] == mkey)
57b0aad2
A
823 {
824 asl_mini_memory_record_free(s, out);
825 *type = ASL_QUERY_MATCH_SLOW;
826 return NULL;
827 }
828 }
829
a83ff38a 830 mval = asl_mini_memory_string_retain(s, val, 0);
57b0aad2
A
831
832 if (out->kvcount == 0)
833 {
834 out->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *));
835 }
836 else
837 {
838 out->kvlist = (mini_mem_string_t **)realloc(out->kvlist, (out->kvcount + 2) * sizeof(mini_mem_string_t *));
839 }
840
841 if (out->kvlist == NULL)
842 {
843 asl_mini_memory_record_free(s, out);
844 *type = ASL_QUERY_MATCH_ERROR;
845 return NULL;
846 }
847
a83ff38a
A
848 out->kvlist[out->kvcount++] = mkey;
849 out->kvlist[out->kvcount++] = mval;
57b0aad2
A
850 }
851 }
852
853 return out;
854}
855
856static uint32_t
857asl_mini_memory_fast_match(asl_mini_memory_t *s, mini_mem_record_t *r, uint32_t qtype, mini_mem_record_t *q)
858{
859 uint32_t i, j;
860
861 if (s == NULL) return 0;
862 if (r == NULL) return 0;
863 if (q == NULL) return 1;
864
865 if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0;
866 if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0;
867 if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0;
868 if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0;
869 if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0;
870 if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0;
871 if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0;
872
873 for (i = 0; i < q->kvcount; i += 2)
874 {
875 for (j = 0; j < r->kvcount; j += 2)
876 {
877 if (q->kvlist[i] == r->kvlist[j])
878 {
879 if (q->kvlist[i + 1] == r->kvlist[j + 1]) break;
880 return 0;
881 }
882 }
883
884 if (j >= r->kvcount) return 0;
885 }
886
887 return 1;
888}
889
890static uint32_t
a83ff38a 891asl_mini_memory_slow_match(asl_mini_memory_t *s, mini_mem_record_t *r, mini_mem_record_t *q, aslmsg rawq)
57b0aad2 892{
a83ff38a 893 aslmsg rawm;
57b0aad2
A
894 uint32_t status;
895
896 rawm = NULL;
897 status = asl_mini_memory_message_decode(s, r, &rawm);
898 if (status != ASL_STATUS_OK) return 0;
899
900 status = 0;
a83ff38a 901 if (asl_msg_cmp((asl_msg_t *)rawq, (asl_msg_t *)rawm) != 0) status = 1;
57b0aad2
A
902 asl_free(rawm);
903 return status;
904}
905
906uint32_t
907asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
908{
909 uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
910 mini_mem_record_t **qp;
a83ff38a 911 aslmsg m;
57b0aad2
A
912
913 if (s == NULL) return ASL_STATUS_INVALID_STORE;
914 if (res == NULL) return ASL_STATUS_INVALID_ARG;
915
916 do_match = 1;
917 qp = NULL;
918 qtype = NULL;
919 rescount = 0;
920
921 if ((query == NULL) || ((query != NULL) && (query->count == 0)))
922 {
923 do_match = 0;
924 }
925 else
926 {
927 qp = (mini_mem_record_t **)calloc(query->count, sizeof(mini_mem_record_t *));
928 if (qp == NULL) return ASL_STATUS_NO_MEMORY;
929
930 qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t));
931 if (qtype == NULL)
932 {
933 free(qp);
934 return ASL_STATUS_NO_MEMORY;
935 }
936
937 do_match = 0;
938 for (i = 0; i < query->count; i++)
939 {
940 qp[i] = asl_mini_memory_query_to_record(s, query->msg[i], &(qtype[i]));
941 if (qtype[i] == ASL_QUERY_MATCH_ERROR)
942 {
943 for (j = 0; j < i; j++) asl_mini_memory_record_free(s, qp[j]);
944 free(qp);
945 free(qtype);
946 return ASL_STATUS_FAILED;
947 }
948
949 if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1;
950 }
951 }
952
953 for (i = 0; i < s->record_count; i++)
954 {
955 if (direction >= 0)
956 {
957 where = (s->record_first + i) % s->record_count;
958 if (s->record[where]->mid == 0) continue;
959 if (s->record[where]->mid >= start_id) break;
960 }
961 else
962 {
963 where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count;
964 if (s->record[where]->mid == 0) continue;
965 if (s->record[where]->mid <= start_id) break;
966 }
967 }
968
c4fdb7d1
A
969 if (i >= s->record_count)
970 {
971 if (qp != NULL)
972 {
973 for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]);
974 free(qp);
975 free(qtype);
976 }
977
978 return ASL_STATUS_OK;
979 }
57b0aad2
A
980
981 start = where;
982
983 /*
984 * loop through records
985 */
986 for (i = 0; i < s->record_count; i++)
987 {
988 if (s->record[where]->mid == 0)
989 {
990 if (direction >= 0)
991 {
992 where++;
993 if (where >= s->record_count) where = 0;
994 }
995 else
996 {
997 if (where == 0) where = s->record_count - 1;
998 else where--;
999 }
1000
1001 if (where == s->record_first) break;
1002 continue;
1003 }
1004
1005 s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR;
1006 *last_id = s->record[where]->mid;
1007 did_match = 1;
1008
1009 if (do_match != 0)
1010 {
1011 did_match = 0;
1012
1013 for (j = 0; (j < query->count) && (did_match == 0); j++)
1014 {
1015 if (qtype[j] == ASL_QUERY_MATCH_TRUE)
1016 {
1017 did_match = 1;
1018 }
a83ff38a
A
1019 else if (qtype[j] == ASL_QUERY_MATCH_FALSE)
1020 {
1021 did_match = 0;
1022 }
57b0aad2
A
1023 else if (qtype[j] == ASL_QUERY_MATCH_SLOW)
1024 {
a83ff38a 1025 did_match = asl_mini_memory_slow_match(s, s->record[where], qp[j], (aslmsg)query->msg[j]);
57b0aad2
A
1026 }
1027 else
1028 {
1029 did_match = asl_mini_memory_fast_match(s, s->record[where], qtype[j], qp[j]);
1030 }
1031 }
1032 }
1033
1034 if (did_match == 1)
1035 {
1036 s->record[where]->flags |= ASL_MINI_MSG_FLAG_SEARCH_MATCH;
1037 rescount++;
1038 if ((count != 0) && (rescount >= count)) break;
1039 }
1040
1041 if (direction >= 0)
1042 {
1043 where++;
1044 if (where >= s->record_count) where = 0;
1045 }
1046 else
1047 {
1048 if (where == 0) where = s->record_count - 1;
1049 else where--;
1050 }
1051
1052 if (where == s->record_first) break;
1053 }
1054
1055 if (query != NULL)
1056 {
1057 for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]);
1058 free(qp);
1059 free(qtype);
1060 }
1061
1062 *res = NULL;
1063 if (rescount == 0) return ASL_STATUS_OK;
1064
1065 *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
1066 if (*res == NULL) return ASL_STATUS_NO_MEMORY;
1067
1068 (*res)->count = rescount;
1069
1070 (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *));
1071 if ((*res)->msg == NULL)
1072 {
1073 free(*res);
1074 *res = NULL;
1075 return ASL_STATUS_NO_MEMORY;
1076 }
1077
1078 where = start;
1079 forever
1080 {
1081 if (s->record[where]->flags & ASL_MINI_MSG_FLAG_SEARCH_MATCH)
1082 {
1083 s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR;
1084
1085 status = asl_mini_memory_message_decode(s, s->record[where], &m);
1086 if (status != ASL_STATUS_OK)
1087 {
1088 aslresponse_free(*res);
1089 *res = NULL;
1090 return status;
1091 }
1092
a83ff38a 1093 (*res)->msg[(*res)->curr++] = (asl_msg_t *)m;
57b0aad2
A
1094 if ((*res)->curr == rescount) break;
1095 }
1096
1097 if (direction >= 0)
1098 {
1099 where++;
1100 if (where >= s->record_count) where = 0;
1101 }
1102 else
1103 {
1104 if (where == 0) where = s->record_count - 1;
1105 else where--;
1106 }
1107
1108 if (where == s->record_first) break;
1109 }
1110
1111 (*res)->curr = 0;
1112 return ASL_STATUS_OK;
1113}