]> git.saurik.com Git - apple/syslog.git/blob - aslcommon/asl_mini_memory.c
0651cb8a78ff12a1e642cfe080eac4486cd2c134
[apple/syslog.git] / aslcommon / asl_mini_memory.c
1 /*
2 * Copyright (c) 2007-2010 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 #include <asl_msg.h>
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(;;)
42 extern time_t asl_parse_time(const char *str);
43 extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
44
45 uint32_t
46 asl_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
56 out = asl_new(ASL_TYPE_MSG);
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
84 uint32_t
85 asl_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
122 uint32_t
123 asl_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
166 static mini_mem_string_t *
167 mem_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 */
193 static uint32_t
194 asl_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 range = top = s->string_count - 1;
208 bot = 0;
209 mid = top / 2;
210
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 mini_mem_string_t *new;
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 new = mem_string_new(str, len, hash);
302 if (new == NULL) return NULL;
303
304 s->string_cache[where] = new;
305 s->string_count++;
306
307 return s->string_cache[where];
308 }
309
310 static uint32_t
311 asl_mini_memory_string_release(asl_mini_memory_t *s, mini_mem_string_t *m)
312 {
313 uint32_t i, where;
314
315 if (s == NULL) return ASL_STATUS_INVALID_STORE;
316 if (m == NULL) return ASL_STATUS_OK;
317
318 if (m->refcount > 0) m->refcount--;
319 if (m->refcount > 0) return ASL_STATUS_OK;
320
321 where = asl_mini_memory_string_cache_search_hash(s, m->hash);
322 if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
323
324 while (s->string_cache[where] != m)
325 {
326 if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
327
328 where++;
329 if (where >= s->string_count) return ASL_STATUS_OK;
330 }
331
332 for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
333
334 free(m);
335 s->string_count--;
336
337 if (s->string_count == 0)
338 {
339 free(s->string_cache);
340 s->string_cache = NULL;
341 return ASL_STATUS_OK;
342 }
343
344 s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *));
345 if (s->string_cache == NULL)
346 {
347 s->string_count = 0;
348 return ASL_STATUS_NO_MEMORY;
349 }
350
351 return ASL_STATUS_OK;
352 }
353
354 /*
355 * Release all a record's strings and reset it's values
356 */
357 static void
358 asl_mini_memory_record_clear(asl_mini_memory_t *s, mini_mem_record_t *r)
359 {
360 uint32_t i;
361
362 if (s == NULL) return;
363 if (r == NULL) return;
364
365 asl_mini_memory_string_release(s, r->sender);
366 asl_mini_memory_string_release(s, r->sender_mach_uuid);
367 asl_mini_memory_string_release(s, r->facility);
368 asl_mini_memory_string_release(s, r->message);
369
370 for (i = 0; i < r->kvcount; i++) asl_mini_memory_string_release(s, r->kvlist[i]);
371
372 if (r->kvlist != NULL) free(r->kvlist);
373 memset(r, 0, sizeof(mini_mem_record_t));
374 }
375
376 static void
377 asl_mini_memory_record_free(asl_mini_memory_t *s, mini_mem_record_t *r)
378 {
379 asl_mini_memory_record_clear(s, r);
380 free(r);
381 }
382
383 /*
384 * Encode an aslmsg as a record structure.
385 * Creates and caches strings.
386 */
387 static uint32_t
388 asl_mini_memory_message_encode(asl_mini_memory_t *s, aslmsg msg)
389 {
390 uint32_t x;
391 mini_mem_string_t *k, *v;
392 mini_mem_record_t *r;
393 const char *key, *val;
394
395 if (s == NULL) return ASL_STATUS_INVALID_STORE;
396 if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
397 if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE;
398
399 r = s->buffer_record;
400
401 memset(r, 0, sizeof(mini_mem_record_t));
402
403 r->flags = 0;
404 r->level = ASL_LEVEL_DEBUG;
405 r->pid = -1;
406 r->ruid = -1;
407 r->rgid = -1;
408 r->time = (uint64_t)-1;
409 r->nano = (uint32_t)-1;
410
411 key = NULL;
412 val = NULL;
413
414 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))
415 {
416 if (key == NULL) continue;
417
418 else if (!strcmp(key, ASL_KEY_TIME))
419 {
420 if (val != NULL) r->time = asl_parse_time(val);
421 }
422 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
423 {
424 if (val != NULL) r->nano = atoi(val);
425 }
426 else if (!strcmp(key, ASL_KEY_SENDER))
427 {
428 if (val != NULL) r->sender = asl_mini_memory_string_retain(s, val, 1);
429 }
430 else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID))
431 {
432 if (val != NULL) r->sender_mach_uuid = asl_mini_memory_string_retain(s, val, 1);
433 }
434 else if (!strcmp(key, ASL_KEY_PID))
435 {
436 if (val != NULL) r->pid = atoi(val);
437 }
438 else if (!strcmp(key, ASL_KEY_LEVEL))
439 {
440 if (val != NULL) r->level = atoi(val);
441 }
442 else if (!strcmp(key, ASL_KEY_MSG))
443 {
444 if (val != NULL) r->message = asl_mini_memory_string_retain(s, val, 1);
445 }
446 else if (!strcmp(key, ASL_KEY_FACILITY))
447 {
448 if (val != NULL) r->facility = asl_mini_memory_string_retain(s, val, 1);
449 }
450 else if (!strcmp(key, ASL_KEY_MSG_ID))
451 {
452 /* Ignore */
453 continue;
454 }
455 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
456 {
457 /* Ignore */
458 continue;
459 }
460 else if (!strcmp(key, ASL_KEY_HOST))
461 {
462 /* Ignore */
463 continue;
464 }
465 else if (!strcmp(key, ASL_KEY_REF_PID))
466 {
467 /* Ignore */
468 continue;
469 }
470 else if (!strcmp(key, ASL_KEY_REF_PROC))
471 {
472 /* Ignore */
473 continue;
474 }
475 else if (!strcmp(key, ASL_KEY_SESSION))
476 {
477 /* Ignore */
478 continue;
479 }
480 else if (!strcmp(key, ASL_KEY_UID))
481 {
482 /* Ignore */
483 continue;
484 }
485 else if (!strcmp(key, ASL_KEY_GID))
486 {
487 /* Ignore */
488 continue;
489 }
490 else if (!strcmp(key, ASL_KEY_READ_UID))
491 {
492 if (((r->flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (val != NULL))
493 {
494 r->ruid = atoi(val);
495 r->flags |= ASL_MSG_FLAG_READ_UID_SET;
496 }
497 }
498 else if (!strcmp(key, ASL_KEY_READ_GID))
499 {
500 if (((r->flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (val != NULL))
501 {
502 r->rgid = atoi(val);
503 r->flags |= ASL_MSG_FLAG_READ_GID_SET;
504 }
505 }
506 else if (!strcmp(key, CFLOG_LOCAL_TIME_KEY))
507 {
508 /* Ignore */
509 continue;
510 }
511 else if (!strcmp(key, CFLOG_THREAD_KEY))
512 {
513 /* Ignore */
514 continue;
515 }
516 else
517 {
518 k = asl_mini_memory_string_retain(s, key, 1);
519 if (k == NULL) continue;
520
521 v = NULL;
522 if (val != NULL) v = asl_mini_memory_string_retain(s, val, 1);
523
524 if (r->kvcount == 0)
525 {
526 r->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *));
527 }
528 else
529 {
530 r->kvlist = (mini_mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mini_mem_string_t *));
531 }
532
533 if (r->kvlist == NULL)
534 {
535 asl_mini_memory_record_clear(s, r);
536 return ASL_STATUS_NO_MEMORY;
537 }
538
539 r->kvlist[r->kvcount++] = k;
540 r->kvlist[r->kvcount++] = v;
541 }
542 }
543
544 return ASL_STATUS_OK;
545 }
546
547 uint32_t
548 asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid)
549 {
550 uint32_t status;
551 mini_mem_record_t *t;
552
553 if (s == NULL) return ASL_STATUS_INVALID_STORE;
554 if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
555
556 /* asl_mini_memory_message_encode creates and caches strings */
557 status = asl_mini_memory_message_encode(s, msg);
558 if (status != ASL_STATUS_OK) return status;
559
560 s->buffer_record->mid = s->next_id;
561 s->next_id++;
562
563 /* clear the first record */
564 t = s->record[s->record_first];
565 asl_mini_memory_record_clear(s, t);
566
567 /* add the new record to the record list (swap in the buffer record) */
568 s->record[s->record_first] = s->buffer_record;
569 s->buffer_record = t;
570
571 /* record list is a circular queue */
572 s->record_first++;
573 if (s->record_first >= s->record_count) s->record_first = 0;
574
575 *mid = s->buffer_record->mid;
576
577 return status;
578 }
579
580 /*
581 * Decodes a record structure.
582 */
583 static uint32_t
584 asl_mini_memory_message_decode(asl_mini_memory_t *s, mini_mem_record_t *r, aslmsg *out)
585 {
586 uint32_t i;
587 aslmsg msg;
588 char tmp[64];
589 const char *key, *val;
590
591 if (s == NULL) return ASL_STATUS_INVALID_STORE;
592 if (r == NULL) return ASL_STATUS_INVALID_ARG;
593 if (out == NULL) return ASL_STATUS_INVALID_ARG;
594
595 *out = NULL;
596
597 msg = asl_new(ASL_TYPE_MSG);
598 if (msg == NULL) return ASL_STATUS_NO_MEMORY;
599
600 /* Message ID */
601 snprintf(tmp, sizeof(tmp), "%u", r->mid);
602 asl_set(msg, ASL_KEY_MSG_ID, tmp);
603
604 /* Level */
605 snprintf(tmp, sizeof(tmp), "%u", r->level);
606 asl_set(msg, ASL_KEY_LEVEL, tmp);
607
608 /* Time */
609 if (r->time != (uint64_t)-1)
610 {
611 snprintf(tmp, sizeof(tmp), "%llu", r->time);
612 asl_set(msg, ASL_KEY_TIME, tmp);
613 }
614
615 /* Nanoseconds */
616 if (r->nano != (uint32_t)-1)
617 {
618 snprintf(tmp, sizeof(tmp), "%u", r->nano);
619 asl_set(msg, ASL_KEY_TIME_NSEC, tmp);
620 }
621
622 /* Sender */
623 if (r->sender != NULL)
624 {
625 asl_set(msg, ASL_KEY_SENDER, r->sender->str);
626 }
627
628 /* Sender mach UUID */
629 if (r->sender_mach_uuid != NULL)
630 {
631 asl_set(msg, ASL_KEY_SENDER_MACH_UUID, r->sender_mach_uuid->str);
632 }
633
634 /* Facility */
635 if (r->facility != NULL)
636 {
637 asl_set(msg, ASL_KEY_FACILITY, r->facility->str);
638 }
639
640 /* PID */
641 if (r->pid != -1)
642 {
643 snprintf(tmp, sizeof(tmp), "%d", r->pid);
644 asl_set(msg, ASL_KEY_PID, tmp);
645 }
646
647 /* Message */
648 if (r->message != NULL)
649 {
650 asl_set(msg, ASL_KEY_MSG, r->message->str);
651 }
652
653 /* ReadUID */
654 if (r->flags & ASL_MSG_FLAG_READ_UID_SET)
655 {
656 snprintf(tmp, sizeof(tmp), "%d", r->ruid);
657 asl_set(msg, ASL_KEY_READ_UID, tmp);
658 }
659
660 /* ReadGID */
661 if (r->flags & ASL_MSG_FLAG_READ_GID_SET)
662 {
663 snprintf(tmp, sizeof(tmp), "%d", r->rgid);
664 asl_set(msg, ASL_KEY_READ_GID, tmp);
665 }
666
667 /* Key - Value List */
668 for (i = 0; i < r->kvcount; i++)
669 {
670 key = NULL;
671 val = NULL;
672
673 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str;
674 i++;
675 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str;
676
677 if (key != NULL) asl_set(msg, key, val);
678 }
679
680 *out = msg;
681 return ASL_STATUS_OK;
682 }
683
684 uint32_t
685 asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid)
686 {
687 uint32_t i, status;
688
689 if (s == NULL) return ASL_STATUS_INVALID_STORE;
690 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
691
692 for (i = 0; i < s->record_count; i++)
693 {
694 if (s->record[i]->mid == 0) break;
695
696 if (s->record[i]->mid == mid)
697 {
698 status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
699 if (status != ASL_STATUS_OK) return status;
700 return asl_mini_memory_message_decode(s, s->record[i], msg);
701 }
702 }
703
704 return ASL_STATUS_INVALID_ID;
705 }
706
707 static mini_mem_record_t *
708 asl_mini_memory_query_to_record(asl_mini_memory_t *s, asl_msg_t *q, uint32_t *type)
709 {
710 mini_mem_record_t *out;
711 uint32_t i, x, op;
712 mini_mem_string_t *mkey, *mval;
713 const char *key, *val;
714
715 if (type == NULL) return NULL;
716
717 if (s == NULL)
718 {
719 *type = ASL_QUERY_MATCH_ERROR;
720 return NULL;
721 }
722
723 /* NULL query matches anything */
724 *type = ASL_QUERY_MATCH_TRUE;
725 if (q == NULL) return NULL;
726 if (asl_msg_count((asl_msg_t *)q) == 0) return NULL;
727
728
729 /* we can only do fast match on equality tests */
730 *type = ASL_QUERY_MATCH_SLOW;
731
732 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))
733 {
734 if (op != ASL_QUERY_OP_EQUAL) return NULL;
735 }
736
737 out = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t));
738 if (out == NULL)
739 {
740 *type = ASL_QUERY_MATCH_ERROR;
741 return NULL;
742 }
743
744 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))
745 {
746 if (key == NULL) continue;
747
748 else if (!strcmp(key, ASL_KEY_MSG_ID))
749 {
750 if (val == NULL) continue;
751
752 if (*type & ASL_QUERY_MATCH_MSG_ID)
753 {
754 asl_mini_memory_record_free(s, out);
755 *type = ASL_QUERY_MATCH_SLOW;
756 return NULL;
757 }
758
759 *type |= ASL_QUERY_MATCH_MSG_ID;
760 out->mid = atoll(val);
761 }
762 else if (!strcmp(key, ASL_KEY_TIME))
763 {
764 if (val == NULL) continue;
765
766 if (*type & ASL_QUERY_MATCH_TIME)
767 {
768 asl_mini_memory_record_free(s, out);
769 *type = ASL_QUERY_MATCH_SLOW;
770 return NULL;
771 }
772
773 *type |= ASL_QUERY_MATCH_TIME;
774 out->time = asl_parse_time(val);
775 }
776 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
777 {
778 if (val == NULL) continue;
779
780 if (*type & ASL_QUERY_MATCH_NANO)
781 {
782 asl_mini_memory_record_free(s, out);
783 *type = ASL_QUERY_MATCH_SLOW;
784 return NULL;
785 }
786
787 *type |= ASL_QUERY_MATCH_NANO;
788 out->nano = atoll(val);
789 }
790 else if (!strcmp(key, ASL_KEY_LEVEL))
791 {
792 if (val == NULL) continue;
793
794 if (*type & ASL_QUERY_MATCH_LEVEL)
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_LEVEL;
802 out->level = atoi(val);
803 }
804 else if (!strcmp(key, ASL_KEY_PID))
805 {
806 if (val == NULL) continue;
807
808 if (*type & ASL_QUERY_MATCH_PID)
809 {
810 asl_mini_memory_record_free(s, out);
811 *type = ASL_QUERY_MATCH_SLOW;
812 return NULL;
813 }
814
815 *type |= ASL_QUERY_MATCH_PID;
816 out->pid = atoi(val);
817 }
818 else if (!strcmp(key, ASL_KEY_READ_UID))
819 {
820 if (val == NULL) continue;
821
822 if (*type & ASL_QUERY_MATCH_RUID)
823 {
824 asl_mini_memory_record_free(s, out);
825 *type = ASL_QUERY_MATCH_SLOW;
826 return NULL;
827 }
828
829 *type |= ASL_QUERY_MATCH_RUID;
830 out->ruid = atoi(val);
831 }
832 else if (!strcmp(key, ASL_KEY_READ_GID))
833 {
834 if (val == NULL) continue;
835
836 if (*type & ASL_QUERY_MATCH_RGID)
837 {
838 asl_mini_memory_record_free(s, out);
839 *type = ASL_QUERY_MATCH_SLOW;
840 return NULL;
841 }
842
843 *type |= ASL_QUERY_MATCH_RGID;
844 out->rgid = atoi(val);
845 }
846 else if (!strcmp(key, ASL_KEY_SENDER))
847 {
848 if (val == NULL) continue;
849
850 if (*type & ASL_QUERY_MATCH_SENDER)
851 {
852 asl_mini_memory_record_free(s, out);
853 *type = ASL_QUERY_MATCH_SLOW;
854 return NULL;
855 }
856
857 *type |= ASL_QUERY_MATCH_SENDER;
858 out->sender = asl_mini_memory_string_retain(s, val, 0);
859 if (out->sender == NULL)
860 {
861 asl_mini_memory_record_free(s, out);
862 *type = ASL_QUERY_MATCH_FALSE;
863 return NULL;
864 }
865 }
866 else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID))
867 {
868 if (val == NULL) continue;
869
870 if (*type & ASL_QUERY_MATCH_SMUUID)
871 {
872 asl_mini_memory_record_free(s, out);
873 *type = ASL_QUERY_MATCH_SLOW;
874 return NULL;
875 }
876
877 *type |= ASL_QUERY_MATCH_SMUUID;
878 out->sender_mach_uuid = asl_mini_memory_string_retain(s, val, 0);
879 if (out->sender_mach_uuid == NULL)
880 {
881 asl_mini_memory_record_free(s, out);
882 *type = ASL_QUERY_MATCH_FALSE;
883 return NULL;
884 }
885 }
886 else if (!strcmp(key, ASL_KEY_FACILITY))
887 {
888 if (val == NULL) continue;
889
890 if (*type & ASL_QUERY_MATCH_FACILITY)
891 {
892 asl_mini_memory_record_free(s, out);
893 *type = ASL_QUERY_MATCH_SLOW;
894 return NULL;
895 }
896
897 *type |= ASL_QUERY_MATCH_FACILITY;
898 out->facility = asl_mini_memory_string_retain(s, val, 0);
899 if (out->facility == NULL)
900 {
901 asl_mini_memory_record_free(s, out);
902 *type = ASL_QUERY_MATCH_FALSE;
903 return NULL;
904 }
905 }
906 else if (!strcmp(key, ASL_KEY_MSG))
907 {
908 if (val == NULL) continue;
909
910 if (*type & ASL_QUERY_MATCH_MESSAGE)
911 {
912 asl_mini_memory_record_free(s, out);
913 *type = ASL_QUERY_MATCH_SLOW;
914 return NULL;
915 }
916
917 *type |= ASL_QUERY_MATCH_MESSAGE;
918 out->message = asl_mini_memory_string_retain(s, val, 0);
919 if (out->message == NULL)
920 {
921 asl_mini_memory_record_free(s, out);
922 *type = ASL_QUERY_MATCH_FALSE;
923 return NULL;
924 }
925 }
926 else
927 {
928 mkey = asl_mini_memory_string_retain(s, key, 0);
929 if (mkey == NULL)
930 {
931 asl_mini_memory_record_free(s, out);
932 *type = ASL_QUERY_MATCH_FALSE;
933 return NULL;
934 }
935
936 for (i = 0; i < out->kvcount; i += 2)
937 {
938 if (out->kvlist[i] == mkey)
939 {
940 asl_mini_memory_record_free(s, out);
941 *type = ASL_QUERY_MATCH_SLOW;
942 return NULL;
943 }
944 }
945
946 mval = asl_mini_memory_string_retain(s, val, 0);
947
948 if (out->kvcount == 0)
949 {
950 out->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *));
951 }
952 else
953 {
954 out->kvlist = (mini_mem_string_t **)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(mini_mem_string_t *));
955 }
956
957 if (out->kvlist == NULL)
958 {
959 asl_mini_memory_record_free(s, out);
960 *type = ASL_QUERY_MATCH_ERROR;
961 return NULL;
962 }
963
964 out->kvlist[out->kvcount++] = mkey;
965 out->kvlist[out->kvcount++] = mval;
966 }
967 }
968
969 return out;
970 }
971
972 static uint32_t
973 asl_mini_memory_fast_match(asl_mini_memory_t *s, mini_mem_record_t *r, uint32_t qtype, mini_mem_record_t *q)
974 {
975 uint32_t i, j;
976
977 if (s == NULL) return 0;
978 if (r == NULL) return 0;
979 if (q == NULL) return 1;
980
981 if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0;
982 if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0;
983 if ((qtype & ASL_QUERY_MATCH_NANO) && (q->nano != r->nano)) return 0;
984 if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0;
985 if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0;
986 if ((qtype & ASL_QUERY_MATCH_RUID) && (q->ruid != r->ruid)) return 0;
987 if ((qtype & ASL_QUERY_MATCH_RGID) && (q->rgid != r->rgid)) return 0;
988 if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0;
989 if ((qtype & ASL_QUERY_MATCH_SMUUID) && (q->sender_mach_uuid != r->sender_mach_uuid)) return 0;
990 if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0;
991 if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0;
992
993 for (i = 0; i < q->kvcount; i += 2)
994 {
995 for (j = 0; j < r->kvcount; j += 2)
996 {
997 if (q->kvlist[i] == r->kvlist[j])
998 {
999 if (q->kvlist[i + 1] == r->kvlist[j + 1]) break;
1000 return 0;
1001 }
1002 }
1003
1004 if (j >= r->kvcount) return 0;
1005 }
1006
1007 return 1;
1008 }
1009
1010 static uint32_t
1011 asl_mini_memory_slow_match(asl_mini_memory_t *s, mini_mem_record_t *r, mini_mem_record_t *q, aslmsg rawq)
1012 {
1013 aslmsg rawm;
1014 uint32_t status;
1015
1016 rawm = NULL;
1017 status = asl_mini_memory_message_decode(s, r, &rawm);
1018 if (status != ASL_STATUS_OK) return 0;
1019
1020 status = 0;
1021 if (asl_msg_cmp((asl_msg_t *)rawq, (asl_msg_t *)rawm) != 0) status = 1;
1022 asl_free(rawm);
1023 return status;
1024 }
1025
1026 uint32_t
1027 asl_mini_memory_match_restricted_uuid(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
1028 {
1029 uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
1030 mini_mem_record_t **qp;
1031 aslmsg m;
1032
1033 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1034 if (res == NULL) return ASL_STATUS_INVALID_ARG;
1035
1036 qp = NULL;
1037 qtype = NULL;
1038 rescount = 0;
1039
1040 if ((query == NULL) || ((query != NULL) && (query->count == 0)))
1041 {
1042 do_match = 0;
1043 }
1044 else
1045 {
1046 qp = (mini_mem_record_t **)calloc(query->count, sizeof(mini_mem_record_t *));
1047 if (qp == NULL) return ASL_STATUS_NO_MEMORY;
1048
1049 qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t));
1050 if (qtype == NULL)
1051 {
1052 free(qp);
1053 return ASL_STATUS_NO_MEMORY;
1054 }
1055
1056 do_match = 0;
1057 for (i = 0; i < query->count; i++)
1058 {
1059 qp[i] = asl_mini_memory_query_to_record(s, query->msg[i], &(qtype[i]));
1060 if (qtype[i] == ASL_QUERY_MATCH_ERROR)
1061 {
1062 for (j = 0; j < i; j++) asl_mini_memory_record_free(s, qp[j]);
1063 free(qp);
1064 free(qtype);
1065 return ASL_STATUS_FAILED;
1066 }
1067
1068 if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1;
1069 }
1070 }
1071
1072 for (i = 0; i < s->record_count; i++)
1073 {
1074 if (direction >= 0)
1075 {
1076 where = (s->record_first + i) % s->record_count;
1077 if (s->record[where]->mid == 0) continue;
1078 if (s->record[where]->mid >= start_id) break;
1079 }
1080 else
1081 {
1082 where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count;
1083 if (s->record[where]->mid == 0) continue;
1084 if (s->record[where]->mid <= start_id) break;
1085 }
1086 }
1087
1088 if (i >= s->record_count)
1089 {
1090 if (qp != NULL)
1091 {
1092 for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]);
1093 free(qp);
1094 free(qtype);
1095 }
1096
1097 return ASL_STATUS_OK;
1098 }
1099
1100 start = where;
1101
1102 /*
1103 * loop through records
1104 */
1105 for (i = 0; i < s->record_count; i++)
1106 {
1107 status = ASL_STATUS_INVALID_ID;
1108 if (s->record[where]->mid != 0) status = asl_core_check_access(s->record[where]->ruid, s->record[where]->rgid, ruid, rgid, s->record[where]->flags);
1109
1110 if ((status == ASL_STATUS_OK) && (uuid_str != NULL))
1111 {
1112 if (s->record[where]->sender_mach_uuid == NULL) status = ASL_STATUS_INVALID_ID;
1113 else if (strcmp(s->record[where]->sender_mach_uuid->str, uuid_str) != 0) status = ASL_STATUS_INVALID_ID;
1114 }
1115
1116 if (status != ASL_STATUS_OK)
1117 {
1118 if (direction >= 0)
1119 {
1120 where++;
1121 if (where >= s->record_count) where = 0;
1122 }
1123 else
1124 {
1125 if (where == 0) where = s->record_count - 1;
1126 else where--;
1127 }
1128
1129 if (where == s->record_first) break;
1130 continue;
1131 }
1132
1133 s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR;
1134 *last_id = s->record[where]->mid;
1135 did_match = 1;
1136
1137 if (do_match != 0)
1138 {
1139 did_match = 0;
1140
1141 for (j = 0; (j < query->count) && (did_match == 0); j++)
1142 {
1143 if (qtype[j] == ASL_QUERY_MATCH_TRUE)
1144 {
1145 did_match = 1;
1146 }
1147 else if (qtype[j] == ASL_QUERY_MATCH_FALSE)
1148 {
1149 did_match = 0;
1150 }
1151 else if (qtype[j] == ASL_QUERY_MATCH_SLOW)
1152 {
1153 did_match = asl_mini_memory_slow_match(s, s->record[where], qp[j], (aslmsg)query->msg[j]);
1154 }
1155 else
1156 {
1157 did_match = asl_mini_memory_fast_match(s, s->record[where], qtype[j], qp[j]);
1158 }
1159 }
1160 }
1161
1162 if (did_match == 1)
1163 {
1164 s->record[where]->flags |= ASL_MINI_MSG_FLAG_SEARCH_MATCH;
1165 rescount++;
1166 if ((count != 0) && (rescount >= count)) break;
1167 }
1168
1169 if (direction >= 0)
1170 {
1171 where++;
1172 if (where >= s->record_count) where = 0;
1173 }
1174 else
1175 {
1176 if (where == 0) where = s->record_count - 1;
1177 else where--;
1178 }
1179
1180 if (where == s->record_first) break;
1181 }
1182
1183 if (query != NULL)
1184 {
1185 for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]);
1186 free(qp);
1187 free(qtype);
1188 }
1189
1190 *res = NULL;
1191 if (rescount == 0) return ASL_STATUS_OK;
1192
1193 *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
1194 if (*res == NULL) return ASL_STATUS_NO_MEMORY;
1195
1196 (*res)->count = rescount;
1197
1198 (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *));
1199 if ((*res)->msg == NULL)
1200 {
1201 free(*res);
1202 *res = NULL;
1203 return ASL_STATUS_NO_MEMORY;
1204 }
1205
1206 where = start;
1207 forever
1208 {
1209 if (s->record[where]->flags & ASL_MINI_MSG_FLAG_SEARCH_MATCH)
1210 {
1211 s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR;
1212
1213 status = asl_mini_memory_message_decode(s, s->record[where], &m);
1214 if (status != ASL_STATUS_OK)
1215 {
1216 aslresponse_free(*res);
1217 *res = NULL;
1218 return status;
1219 }
1220
1221 (*res)->msg[(*res)->curr++] = (asl_msg_t *)m;
1222 if ((*res)->curr == rescount) break;
1223 }
1224
1225 if (direction >= 0)
1226 {
1227 where++;
1228 if (where >= s->record_count) where = 0;
1229 }
1230 else
1231 {
1232 if (where == 0) where = s->record_count - 1;
1233 else where--;
1234 }
1235
1236 if (where == s->record_first) break;
1237 }
1238
1239 (*res)->curr = 0;
1240 return ASL_STATUS_OK;
1241 }
1242
1243 uint32_t
1244 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, int32_t ruid, int32_t rgid)
1245 {
1246 return asl_mini_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, direction, ruid, rgid, NULL);
1247 }