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