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