]> git.saurik.com Git - apple/syslog.git/blob - aslcommon/asl_memory.c
1bf140f63f4a16d62de1734306f01b052f2f16aa
[apple/syslog.git] / aslcommon / asl_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_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 2000
36 #define MEM_STRING_HEADER_SIZE 8
37
38 #define forever for(;;)
39 extern time_t asl_parse_time(const char *str);
40 extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
41
42 uint32_t
43 asl_memory_statistics(asl_memory_t *s, aslmsg *msg)
44 {
45 aslmsg out;
46 uint32_t i, n;
47 uint64_t size;
48 char str[256];
49
50 if (s == NULL) return ASL_STATUS_INVALID_STORE;
51 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
52
53 out = asl_new(ASL_TYPE_MSG);
54 if (out == NULL) return ASL_STATUS_NO_MEMORY;
55
56 size = sizeof(asl_memory_t);
57 size += ((s->record_count + 1) * sizeof(mem_record_t));
58
59 for (i = 0; i < s->string_count; i++)
60 {
61 size += MEM_STRING_HEADER_SIZE;
62 if (((mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mem_string_t *)s->string_cache[i])->str) + 1);
63 }
64
65 snprintf(str, sizeof(str), "%llu", size);
66 asl_set(out, "Size", str);
67
68 n = 0;
69 for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++;
70
71 snprintf(str, sizeof(str), "%u", n);
72 asl_set(out, "RecordCount", str);
73
74 snprintf(str, sizeof(str), "%u", s->string_count);
75 asl_set(out, "StringCount", str);
76
77 *msg = out;
78 return ASL_STATUS_OK;
79 }
80
81 uint32_t
82 asl_memory_close(asl_memory_t *s)
83 {
84 uint32_t i;
85
86 if (s == NULL) return ASL_STATUS_OK;
87
88 if (s->record != NULL)
89 {
90 for (i = 0; i < s->record_count; i++)
91 {
92 if (s->record[i] != NULL) free(s->record[i]);
93 s->record[i] = NULL;
94 }
95
96 free(s->record);
97 s->record = NULL;
98 }
99
100 if (s->buffer_record != NULL) free(s->buffer_record);
101
102 if (s->string_cache != NULL)
103 {
104 for (i = 0; i < s->string_count; i++)
105 {
106 if (s->string_cache[i] != NULL) free(s->string_cache[i]);
107 s->string_cache[i] = NULL;
108 }
109
110 free(s->string_cache);
111 s->string_cache = NULL;
112 }
113
114 free(s);
115
116 return ASL_STATUS_OK;
117 }
118
119 uint32_t
120 asl_memory_open(uint32_t max_records, asl_memory_t **s)
121 {
122 asl_memory_t *out;
123 uint32_t i;
124
125 if (s == NULL) return ASL_STATUS_INVALID_ARG;
126
127 if (max_records == 0) max_records = DEFAULT_MAX_RECORDS;
128
129 out = calloc(1, sizeof(asl_memory_t));
130 if (out == NULL) return ASL_STATUS_NO_MEMORY;
131
132 out->record_count = max_records;
133 out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *));
134 if (out->record == NULL)
135 {
136 free(out);
137 return ASL_STATUS_NO_MEMORY;
138 }
139
140 for (i = 0; i < max_records; i++)
141 {
142 out->record[i] = (mem_record_t *)calloc(1, sizeof(mem_record_t));
143 if (out->record[i] == NULL)
144 {
145 asl_memory_close(out);
146 return ASL_STATUS_NO_MEMORY;
147 }
148 }
149
150 out->buffer_record = (mem_record_t *)calloc(1, sizeof(mem_record_t));
151 if (out->buffer_record == NULL)
152 {
153 asl_memory_close(out);
154 return ASL_STATUS_NO_MEMORY;
155 }
156
157 *s = out;
158 return ASL_STATUS_OK;
159 }
160
161 static mem_string_t *
162 mem_string_new(const char *str, uint32_t len, uint32_t hash)
163 {
164 mem_string_t *out;
165 size_t ss;
166
167 if (str == NULL) return NULL;
168
169 ss = MEM_STRING_HEADER_SIZE + len + 1;
170 out = (mem_string_t *)calloc(1, ss);
171 if (out == NULL) return NULL;
172
173 out->hash = hash;
174 out->refcount = 1;
175 memcpy(out->str, str, len);
176
177 return out;
178 }
179
180 /*
181 * Find the first hash greater than or equal to a given hash in the string cache.
182 * Return s->string_count if hash is greater that or equal to last hash in the string cache.
183 * Caller must check if the hashes match or not.
184 *
185 * This routine is used both to find strings in the cache and to determine where to insert
186 * new strings. Note that the caller needs to do extra work after calling this routine.
187 */
188 static uint32_t
189 asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash)
190 {
191 uint32_t top, bot, mid, range;
192 mem_string_t *ms;
193
194 if (s->string_count == 0) return 0;
195 if (s->string_count == 1)
196 {
197 ms = (mem_string_t *)s->string_cache[0];
198 if (hash < ms->hash) return 0;
199 return 1;
200 }
201
202 range = top = s->string_count - 1;
203 bot = 0;
204 mid = top / 2;
205
206 while (range > 1)
207 {
208 ms = (mem_string_t *)s->string_cache[mid];
209
210 if (hash == ms->hash)
211 {
212 while (mid > 0)
213 {
214 ms = (mem_string_t *)s->string_cache[mid - 1];
215 if (hash != ms->hash) break;
216 mid--;
217 }
218
219 return mid;
220 }
221 else
222 {
223 ms = (mem_string_t *)s->string_cache[mid];
224 if (hash < ms->hash) top = mid;
225 else bot = mid;
226 }
227
228 range = top - bot;
229 mid = bot + (range / 2);
230 }
231
232 ms = (mem_string_t *)s->string_cache[bot];
233 if (hash <= ms->hash) return bot;
234
235 ms = (mem_string_t *)s->string_cache[top];
236 if (hash <= ms->hash) return top;
237
238 return s->string_count;
239 }
240
241 /*
242 * Search the string cache.
243 * If the string is in the cache, increment refcount and return it.
244 * If the string is not in cache and create flag is on, create a new string.
245 * Otherwise, return NULL.
246 */
247 static mem_string_t *
248 asl_memory_string_retain(asl_memory_t *s, const char *str, int create)
249 {
250 uint32_t i, where, hash, len;
251 mem_string_t *new;
252
253 if (s == NULL) return NULL;
254 if (str == NULL) return NULL;
255 len = strlen(str);
256
257 /* check the cache */
258 hash = asl_core_string_hash(str, len);
259 where = asl_memory_string_cache_search_hash(s, hash);
260
261 /* asl_memory_string_cache_search_hash just tells us where to look */
262 if (where < s->string_count)
263 {
264 while (((mem_string_t *)(s->string_cache[where]))->hash == hash)
265 {
266 if (!strcmp(str, ((mem_string_t *)(s->string_cache[where]))->str))
267 {
268 ((mem_string_t *)(s->string_cache[where]))->refcount++;
269 return s->string_cache[where];
270 }
271
272 where++;
273 }
274 }
275
276 /* not found */
277 if (create == 0) return NULL;
278
279 /* create a new mem_string_t and insert into the cache at index 'where' */
280 if (s->string_count == 0)
281 {
282 s->string_cache = (void **)calloc(1, sizeof(void *));
283 }
284 else
285 {
286 s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
287 for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
288 }
289
290 if (s->string_cache == NULL)
291 {
292 s->string_count = 0;
293 return NULL;
294 }
295
296 new = mem_string_new(str, len, hash);
297 if (new == NULL) return NULL;
298
299 s->string_cache[where] = new;
300 s->string_count++;
301
302 return s->string_cache[where];
303 }
304
305 static uint32_t
306 asl_memory_string_release(asl_memory_t *s, mem_string_t *m)
307 {
308 uint32_t i, where;
309
310 if (s == NULL) return ASL_STATUS_INVALID_STORE;
311 if (m == NULL) return ASL_STATUS_OK;
312
313 if (m->refcount > 0) m->refcount--;
314 if (m->refcount > 0) return ASL_STATUS_OK;
315
316 where = asl_memory_string_cache_search_hash(s, m->hash);
317 if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
318
319 while (s->string_cache[where] != m)
320 {
321 if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
322
323 where++;
324 if (where >= s->string_count) return ASL_STATUS_OK;
325 }
326
327 for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
328
329 free(m);
330 s->string_count--;
331
332 if (s->string_count == 0)
333 {
334 free(s->string_cache);
335 s->string_cache = NULL;
336 return ASL_STATUS_OK;
337 }
338
339 s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *));
340 if (s->string_cache == NULL)
341 {
342 s->string_count = 0;
343 return ASL_STATUS_NO_MEMORY;
344 }
345
346 return ASL_STATUS_OK;
347 }
348
349 /*
350 * Release all a record's strings and reset it's values
351 */
352 static void
353 asl_memory_record_clear(asl_memory_t *s, mem_record_t *r)
354 {
355 uint32_t i;
356
357 if (s == NULL) return;
358 if (r == NULL) return;
359
360 asl_memory_string_release(s, r->host);
361 asl_memory_string_release(s, r->sender);
362 asl_memory_string_release(s, r->sender_mach_uuid);
363 asl_memory_string_release(s, r->facility);
364 asl_memory_string_release(s, r->message);
365 asl_memory_string_release(s, r->refproc);
366 asl_memory_string_release(s, r->session);
367
368 for (i = 0; i < r->kvcount; i++) asl_memory_string_release(s, r->kvlist[i]);
369
370 if (r->kvlist != NULL) free(r->kvlist);
371 memset(r, 0, sizeof(mem_record_t));
372 }
373
374 static void
375 asl_memory_record_free(asl_memory_t *s, mem_record_t *r)
376 {
377 asl_memory_record_clear(s, r);
378 free(r);
379 }
380
381 /*
382 * Encode an aslmsg as a record structure.
383 * Creates and caches strings.
384 */
385 static uint32_t
386 asl_memory_message_encode(asl_memory_t *s, aslmsg msg)
387 {
388 uint32_t x;
389 mem_string_t *k, *v;
390 mem_record_t *r;
391 const char *key, *val;
392
393 if (s == NULL) return ASL_STATUS_INVALID_STORE;
394 if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
395 if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE;
396
397 r = s->buffer_record;
398
399 memset(r, 0, sizeof(mem_record_t));
400
401 r->flags = 0;
402 r->level = ASL_LEVEL_DEBUG;
403 r->pid = -1;
404 r->uid = -2;
405 r->gid = -2;
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_HOST))
427 {
428 if (val != NULL) r->host = asl_memory_string_retain(s, val, 1);
429 }
430 else if (!strcmp(key, ASL_KEY_SENDER))
431 {
432 if (val != NULL) r->sender = asl_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_REF_PID))
439 {
440 if (val != NULL) r->refpid = atoi(val);
441 }
442 else if (!strcmp(key, ASL_KEY_UID))
443 {
444 if (val != NULL) r->uid = atoi(val);
445 }
446 else if (!strcmp(key, ASL_KEY_GID))
447 {
448 if (val != NULL) r->gid = atoi(val);
449 }
450 else if (!strcmp(key, ASL_KEY_LEVEL))
451 {
452 if (val != NULL) r->level = atoi(val);
453 }
454 else if (!strcmp(key, ASL_KEY_MSG))
455 {
456 if (val != NULL) r->message = asl_memory_string_retain(s, val, 1);
457 }
458 else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID))
459 {
460 if (val != NULL) r->sender_mach_uuid = asl_memory_string_retain(s, val, 1);
461 }
462 else if (!strcmp(key, ASL_KEY_FACILITY))
463 {
464 if (val != NULL) r->facility = asl_memory_string_retain(s, val, 1);
465 }
466 else if (!strcmp(key, ASL_KEY_REF_PROC))
467 {
468 if (val != NULL) r->refproc = asl_memory_string_retain(s, val, 1);
469 }
470 else if (!strcmp(key, ASL_KEY_SESSION))
471 {
472 if (val != NULL) r->session = asl_memory_string_retain(s, val, 1);
473 }
474 else if (!strcmp(key, ASL_KEY_READ_UID))
475 {
476 if (((r->flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (val != NULL))
477 {
478 r->ruid = atoi(val);
479 r->flags |= ASL_MSG_FLAG_READ_UID_SET;
480 }
481 }
482 else if (!strcmp(key, ASL_KEY_READ_GID))
483 {
484 if (((r->flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (val != NULL))
485 {
486 r->rgid = atoi(val);
487 r->flags |= ASL_MSG_FLAG_READ_GID_SET;
488 }
489 }
490 else if (!strcmp(key, ASL_KEY_MSG_ID))
491 {
492 /* Ignore */
493 continue;
494 }
495 else
496 {
497 k = asl_memory_string_retain(s, key, 1);
498 if (k == NULL) continue;
499
500 v = NULL;
501 if (val != NULL) v = asl_memory_string_retain(s, val, 1);
502
503 if (r->kvcount == 0)
504 {
505 r->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *));
506 }
507 else
508 {
509 r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *));
510 }
511
512 if (r->kvlist == NULL)
513 {
514 asl_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
526 uint32_t
527 asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid)
528 {
529 uint32_t status;
530 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_memory_message_encode creates and caches strings */
536 status = asl_memory_message_encode(s, msg);
537 if (status != ASL_STATUS_OK) return status;
538
539 if (*mid != 0)
540 {
541 s->buffer_record->mid = *mid;
542 }
543 else
544 {
545 s->buffer_record->mid = asl_core_new_msg_id(0);
546 *mid = s->buffer_record->mid;
547 }
548
549 /* clear the first record */
550 t = s->record[s->record_first];
551 asl_memory_record_clear(s, t);
552
553 /* add the new record to the record list (swap in the buffer record) */
554 s->record[s->record_first] = s->buffer_record;
555 s->buffer_record = t;
556
557 /* record list is a circular queue */
558 s->record_first++;
559 if (s->record_first >= s->record_count) s->record_first = 0;
560
561 return status;
562 }
563
564 /*
565 * Decodes a record structure.
566 */
567 static uint32_t
568 asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, aslmsg *out)
569 {
570 uint32_t i;
571 aslmsg msg;
572 char tmp[64];
573 const char *key, *val;
574
575 if (s == NULL) return ASL_STATUS_INVALID_STORE;
576 if (r == NULL) return ASL_STATUS_INVALID_ARG;
577 if (out == NULL) return ASL_STATUS_INVALID_ARG;
578
579 *out = NULL;
580
581 msg = asl_new(ASL_TYPE_MSG);
582 if (msg == NULL) return ASL_STATUS_NO_MEMORY;
583
584 /* Message ID */
585 snprintf(tmp, sizeof(tmp), "%llu", r->mid);
586 asl_set(msg, ASL_KEY_MSG_ID, tmp);
587
588 /* Level */
589 snprintf(tmp, sizeof(tmp), "%u", r->level);
590 asl_set(msg, ASL_KEY_LEVEL, tmp);
591
592 /* Time */
593 if (r->time != (uint64_t)-1)
594 {
595 snprintf(tmp, sizeof(tmp), "%llu", r->time);
596 asl_set(msg, ASL_KEY_TIME, tmp);
597 }
598
599 /* Nanoseconds */
600 if (r->nano != (uint32_t)-1)
601 {
602 snprintf(tmp, sizeof(tmp), "%u", r->nano);
603 asl_set(msg, ASL_KEY_TIME_NSEC, tmp);
604 }
605
606 /* Host */
607 if (r->host != NULL)
608 {
609 asl_set(msg, ASL_KEY_HOST, r->host->str);
610 }
611
612 /* Sender */
613 if (r->sender != NULL)
614 {
615 asl_set(msg, ASL_KEY_SENDER, r->sender->str);
616 }
617
618 /* Sender mach UUID */
619 if (r->sender_mach_uuid != NULL)
620 {
621 asl_set(msg, ASL_KEY_SENDER_MACH_UUID, r->sender_mach_uuid->str);
622 }
623
624 /* Facility */
625 if (r->facility != NULL)
626 {
627 asl_set(msg, ASL_KEY_FACILITY, r->facility->str);
628 }
629
630 /* Ref Proc */
631 if (r->refproc != NULL)
632 {
633 asl_set(msg, ASL_KEY_REF_PROC, r->refproc->str);
634 }
635
636 /* Session */
637 if (r->session != NULL)
638 {
639 asl_set(msg, ASL_KEY_SESSION, r->session->str);
640 }
641
642 /* PID */
643 if (r->pid != -1)
644 {
645 snprintf(tmp, sizeof(tmp), "%d", r->pid);
646 asl_set(msg, ASL_KEY_PID, tmp);
647 }
648
649 /* REF PID */
650 if (r->refpid != 0)
651 {
652 snprintf(tmp, sizeof(tmp), "%d", r->refpid);
653 asl_set(msg, ASL_KEY_REF_PID, tmp);
654 }
655
656 /* UID */
657 if (r->uid != -2)
658 {
659 snprintf(tmp, sizeof(tmp), "%d", r->uid);
660 asl_set(msg, ASL_KEY_UID, tmp);
661 }
662
663 /* GID */
664 if (r->gid != -2)
665 {
666 snprintf(tmp, sizeof(tmp), "%d", r->gid);
667 asl_set(msg, ASL_KEY_GID, tmp);
668 }
669
670 /* Message */
671 if (r->message != NULL)
672 {
673 asl_set(msg, ASL_KEY_MSG, r->message->str);
674 }
675
676 /* ReadUID */
677 if (r->flags & ASL_MSG_FLAG_READ_UID_SET)
678 {
679 snprintf(tmp, sizeof(tmp), "%d", r->ruid);
680 asl_set(msg, ASL_KEY_READ_UID, tmp);
681 }
682
683 /* ReadGID */
684 if (r->flags & ASL_MSG_FLAG_READ_GID_SET)
685 {
686 snprintf(tmp, sizeof(tmp), "%d", r->rgid);
687 asl_set(msg, ASL_KEY_READ_GID, tmp);
688 }
689
690 /* Key - Value List */
691 for (i = 0; i < r->kvcount; i++)
692 {
693 key = NULL;
694 val = NULL;
695
696 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str;
697 i++;
698 if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str;
699
700 if (key != NULL) asl_set(msg, key, val);
701 }
702
703 *out = msg;
704 return ASL_STATUS_OK;
705 }
706
707 uint32_t
708 asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid)
709 {
710 uint32_t i, status;
711
712 if (s == NULL) return ASL_STATUS_INVALID_STORE;
713 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
714
715 for (i = 0; i < s->record_count; i++)
716 {
717 if (s->record[i]->mid == 0) break;
718
719 if (s->record[i]->mid == mid)
720 {
721 status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
722 if (status != ASL_STATUS_OK) return status;
723 return asl_memory_message_decode(s, s->record[i], msg);
724 }
725 }
726
727 return ASL_STATUS_INVALID_ID;
728 }
729
730 static mem_record_t *
731 asl_memory_query_to_record(asl_memory_t *s, aslmsg q, uint32_t *type)
732 {
733 mem_record_t *out;
734 uint32_t i, x, op;
735 mem_string_t *mkey, *mval;
736 const char *key, *val;
737
738 if (type == NULL) return NULL;
739
740 if (s == NULL)
741 {
742 *type = ASL_QUERY_MATCH_ERROR;
743 return NULL;
744 }
745
746 /* NULL query matches anything */
747 *type = ASL_QUERY_MATCH_TRUE;
748 if (q == NULL) return NULL;
749 if (asl_msg_count((asl_msg_t *)q) == 0) return NULL;
750
751
752 /* we can only do fast match on equality tests */
753 *type = ASL_QUERY_MATCH_SLOW;
754
755 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))
756 {
757 if (op != ASL_QUERY_OP_EQUAL) return NULL;
758 }
759
760 out = (mem_record_t *)calloc(1, sizeof(mem_record_t));
761 if (out == NULL)
762 {
763 *type = ASL_QUERY_MATCH_ERROR;
764 return NULL;
765 }
766
767 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))
768 {
769 if (key == NULL) continue;
770
771 else if (!strcmp(key, ASL_KEY_MSG_ID))
772 {
773 if (val == NULL) continue;
774
775 if (*type & ASL_QUERY_MATCH_MSG_ID)
776 {
777 asl_memory_record_free(s, out);
778 *type = ASL_QUERY_MATCH_SLOW;
779 return NULL;
780 }
781
782 *type |= ASL_QUERY_MATCH_MSG_ID;
783 out->mid = atoll(val);
784 }
785 else if (!strcmp(key, ASL_KEY_TIME))
786 {
787 if (val == NULL) continue;
788
789 if (*type & ASL_QUERY_MATCH_TIME)
790 {
791 asl_memory_record_free(s, out);
792 *type = ASL_QUERY_MATCH_SLOW;
793 return NULL;
794 }
795
796 *type |= ASL_QUERY_MATCH_TIME;
797 out->time = asl_parse_time(val);
798 }
799 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
800 {
801 if (val == NULL) continue;
802
803 if (*type & ASL_QUERY_MATCH_NANO)
804 {
805 asl_memory_record_free(s, out);
806 *type = ASL_QUERY_MATCH_SLOW;
807 return NULL;
808 }
809
810 *type |= ASL_QUERY_MATCH_NANO;
811 out->nano = atoll(val);
812 }
813 else if (!strcmp(key, ASL_KEY_LEVEL))
814 {
815 if (val == NULL) continue;
816
817 if (*type & ASL_QUERY_MATCH_LEVEL)
818 {
819 asl_memory_record_free(s, out);
820 *type = ASL_QUERY_MATCH_SLOW;
821 return NULL;
822 }
823
824 *type |= ASL_QUERY_MATCH_LEVEL;
825 out->level = atoi(val);
826 }
827 else if (!strcmp(key, ASL_KEY_PID))
828 {
829 if (val == NULL) continue;
830
831 if (*type & ASL_QUERY_MATCH_PID)
832 {
833 asl_memory_record_free(s, out);
834 *type = ASL_QUERY_MATCH_SLOW;
835 return NULL;
836 }
837
838 *type |= ASL_QUERY_MATCH_PID;
839 out->pid = atoi(val);
840 }
841 else if (!strcmp(key, ASL_KEY_UID))
842 {
843 if (val == NULL) continue;
844
845 if (*type & ASL_QUERY_MATCH_UID)
846 {
847 asl_memory_record_free(s, out);
848 *type = ASL_QUERY_MATCH_SLOW;
849 return NULL;
850 }
851
852 *type |= ASL_QUERY_MATCH_UID;
853 out->uid = atoi(val);
854 }
855 else if (!strcmp(key, ASL_KEY_GID))
856 {
857 if (val == NULL) continue;
858
859 if (*type & ASL_QUERY_MATCH_GID)
860 {
861 asl_memory_record_free(s, out);
862 *type = ASL_QUERY_MATCH_SLOW;
863 return NULL;
864 }
865
866 *type |= ASL_QUERY_MATCH_GID;
867 out->gid = atoi(val);
868 }
869 else if (!strcmp(key, ASL_KEY_READ_UID))
870 {
871 if (val == NULL) continue;
872
873 if (*type & ASL_QUERY_MATCH_RUID)
874 {
875 asl_memory_record_free(s, out);
876 *type = ASL_QUERY_MATCH_SLOW;
877 return NULL;
878 }
879
880 *type |= ASL_QUERY_MATCH_RUID;
881 out->ruid = atoi(val);
882 }
883 else if (!strcmp(key, ASL_KEY_READ_GID))
884 {
885 if (val == NULL) continue;
886
887 if (*type & ASL_QUERY_MATCH_RGID)
888 {
889 asl_memory_record_free(s, out);
890 *type = ASL_QUERY_MATCH_SLOW;
891 return NULL;
892 }
893
894 *type |= ASL_QUERY_MATCH_RGID;
895 out->rgid = atoi(val);
896 }
897 else if (!strcmp(key, ASL_KEY_REF_PID))
898 {
899 if (val == NULL) continue;
900
901 if (*type & ASL_QUERY_MATCH_REF_PID)
902 {
903 asl_memory_record_free(s, out);
904 *type = ASL_QUERY_MATCH_SLOW;
905 return NULL;
906 }
907
908 *type |= ASL_QUERY_MATCH_REF_PID;
909 out->refpid = atoi(val);
910 }
911 else if (!strcmp(key, ASL_KEY_HOST))
912 {
913 if (val == NULL) continue;
914
915 if (*type & ASL_QUERY_MATCH_HOST)
916 {
917 asl_memory_record_free(s, out);
918 *type = ASL_QUERY_MATCH_SLOW;
919 return NULL;
920 }
921
922 *type |= ASL_QUERY_MATCH_HOST;
923 out->host = asl_memory_string_retain(s, val, 0);
924 if (out->host == NULL)
925 {
926 asl_memory_record_free(s, out);
927 *type = ASL_QUERY_MATCH_FALSE;
928 return NULL;
929 }
930 }
931 else if (!strcmp(key, ASL_KEY_SENDER))
932 {
933 if (val == NULL) continue;
934
935 if (*type & ASL_QUERY_MATCH_SENDER)
936 {
937 asl_memory_record_free(s, out);
938 *type = ASL_QUERY_MATCH_SLOW;
939 return NULL;
940 }
941
942 *type |= ASL_QUERY_MATCH_SENDER;
943 out->sender = asl_memory_string_retain(s, val, 0);
944 if (out->sender == NULL)
945 {
946 asl_memory_record_free(s, out);
947 *type = ASL_QUERY_MATCH_FALSE;
948 return NULL;
949 }
950 }
951 else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID))
952 {
953 if (val == NULL) continue;
954
955 if (*type & ASL_QUERY_MATCH_SMUUID)
956 {
957 asl_memory_record_free(s, out);
958 *type = ASL_QUERY_MATCH_SLOW;
959 return NULL;
960 }
961
962 *type |= ASL_QUERY_MATCH_SMUUID;
963 out->sender = asl_memory_string_retain(s, val, 0);
964 if (out->sender_mach_uuid == NULL)
965 {
966 asl_memory_record_free(s, out);
967 *type = ASL_QUERY_MATCH_FALSE;
968 return NULL;
969 }
970 }
971 else if (!strcmp(key, ASL_KEY_FACILITY))
972 {
973 if (val == NULL) continue;
974
975 if (*type & ASL_QUERY_MATCH_FACILITY)
976 {
977 asl_memory_record_free(s, out);
978 *type = ASL_QUERY_MATCH_SLOW;
979 return NULL;
980 }
981
982 *type |= ASL_QUERY_MATCH_FACILITY;
983 out->facility = asl_memory_string_retain(s, val, 0);
984 if (out->facility == NULL)
985 {
986 asl_memory_record_free(s, out);
987 *type = ASL_QUERY_MATCH_FALSE;
988 return NULL;
989 }
990 }
991 else if (!strcmp(key, ASL_KEY_MSG))
992 {
993 if (val == NULL) continue;
994
995 if (*type & ASL_QUERY_MATCH_MESSAGE)
996 {
997 asl_memory_record_free(s, out);
998 *type = ASL_QUERY_MATCH_SLOW;
999 return NULL;
1000 }
1001
1002 *type |= ASL_QUERY_MATCH_MESSAGE;
1003 out->message = asl_memory_string_retain(s, val, 0);
1004 if (out->message == NULL)
1005 {
1006 asl_memory_record_free(s, out);
1007 *type = ASL_QUERY_MATCH_FALSE;
1008 return NULL;
1009 }
1010 }
1011 else if (!strcmp(key, ASL_KEY_REF_PROC))
1012 {
1013 if (val == NULL) continue;
1014
1015 if (*type & ASL_QUERY_MATCH_REF_PROC)
1016 {
1017 asl_memory_record_free(s, out);
1018 *type = ASL_QUERY_MATCH_SLOW;
1019 return NULL;
1020 }
1021
1022 *type |= ASL_QUERY_MATCH_REF_PROC;
1023 out->refproc = asl_memory_string_retain(s, val, 0);
1024 if (out->refproc == NULL)
1025 {
1026 asl_memory_record_free(s, out);
1027 *type = ASL_QUERY_MATCH_FALSE;
1028 return NULL;
1029 }
1030 }
1031 else if (!strcmp(key, ASL_KEY_SESSION))
1032 {
1033 if (val == NULL) continue;
1034
1035 if (*type & ASL_QUERY_MATCH_SESSION)
1036 {
1037 asl_memory_record_free(s, out);
1038 *type = ASL_QUERY_MATCH_SLOW;
1039 return NULL;
1040 }
1041
1042 *type |= ASL_QUERY_MATCH_SESSION;
1043 out->session = asl_memory_string_retain(s, val, 0);
1044 if (out->session == NULL)
1045 {
1046 asl_memory_record_free(s, out);
1047 *type = ASL_QUERY_MATCH_FALSE;
1048 return NULL;
1049 }
1050 }
1051 else
1052 {
1053 mkey = asl_memory_string_retain(s, key, 0);
1054 if (mkey == NULL)
1055 {
1056 asl_memory_record_free(s, out);
1057 *type = ASL_QUERY_MATCH_FALSE;
1058 return NULL;
1059 }
1060
1061 for (i = 0; i < out->kvcount; i += 2)
1062 {
1063 if (out->kvlist[i] == mkey)
1064 {
1065 asl_memory_record_free(s, out);
1066 *type = ASL_QUERY_MATCH_SLOW;
1067 return NULL;
1068 }
1069 }
1070
1071 mval = asl_memory_string_retain(s, val, 0);
1072
1073 if (out->kvcount == 0)
1074 {
1075 out->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *));
1076 }
1077 else
1078 {
1079 out->kvlist = (mem_string_t **)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(mem_string_t *));
1080 }
1081
1082 if (out->kvlist == NULL)
1083 {
1084 asl_memory_record_free(s, out);
1085 *type = ASL_QUERY_MATCH_ERROR;
1086 return NULL;
1087 }
1088
1089 out->kvlist[out->kvcount++] = mkey;
1090 out->kvlist[out->kvcount++] = mval;
1091 }
1092 }
1093
1094 return out;
1095 }
1096
1097 static uint32_t
1098 asl_memory_fast_match(asl_memory_t *s, mem_record_t *r, uint32_t qtype, mem_record_t *q)
1099 {
1100 uint32_t i, j;
1101
1102 if (s == NULL) return 0;
1103 if (r == NULL) return 0;
1104 if (q == NULL) return 1;
1105
1106 if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0;
1107 if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0;
1108 if ((qtype & ASL_QUERY_MATCH_NANO) && (q->nano != r->nano)) return 0;
1109 if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0;
1110 if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0;
1111 if ((qtype & ASL_QUERY_MATCH_UID) && (q->uid != r->uid)) return 0;
1112 if ((qtype & ASL_QUERY_MATCH_GID) && (q->gid != r->gid)) return 0;
1113 if ((qtype & ASL_QUERY_MATCH_RUID) && (q->ruid != r->ruid)) return 0;
1114 if ((qtype & ASL_QUERY_MATCH_RGID) && (q->rgid != r->rgid)) return 0;
1115 if ((qtype & ASL_QUERY_MATCH_REF_PID) && (q->refpid != r->refpid)) return 0;
1116 if ((qtype & ASL_QUERY_MATCH_HOST) && (q->host != r->host)) return 0;
1117 if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0;
1118 if ((qtype & ASL_QUERY_MATCH_SMUUID) && (q->sender_mach_uuid != r->sender_mach_uuid)) return 0;
1119 if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0;
1120 if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0;
1121 if ((qtype & ASL_QUERY_MATCH_REF_PROC) && (q->refproc != r->refproc)) return 0;
1122 if ((qtype & ASL_QUERY_MATCH_SESSION) && (q->session != r->session)) return 0;
1123
1124 for (i = 0; i < q->kvcount; i += 2)
1125 {
1126 for (j = 0; j < r->kvcount; j += 2)
1127 {
1128 if (q->kvlist[i] == r->kvlist[j])
1129 {
1130 if (q->kvlist[i + 1] == r->kvlist[j + 1]) break;
1131 return 0;
1132 }
1133 }
1134
1135 if (j >= r->kvcount) return 0;
1136 }
1137
1138 return 1;
1139 }
1140
1141 static uint32_t
1142 asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, aslmsg rawq)
1143 {
1144 aslmsg rawm;
1145 uint32_t status;
1146
1147 rawm = NULL;
1148 status = asl_memory_message_decode(s, r, &rawm);
1149 if (status != ASL_STATUS_OK) return 0;
1150
1151 status = 0;
1152 if (asl_msg_cmp((asl_msg_t *)rawq, (asl_msg_t *)rawm) != 0) status = 1;
1153 asl_free(rawm);
1154 return status;
1155 }
1156
1157 uint32_t
1158 asl_memory_match_restricted_uuid(asl_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)
1159 {
1160 uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
1161 mem_record_t **qp;
1162 aslmsg m;
1163
1164 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1165 if (res == NULL) return ASL_STATUS_INVALID_ARG;
1166
1167 qp = NULL;
1168 qtype = NULL;
1169 rescount = 0;
1170
1171 if ((query == NULL) || ((query != NULL) && (query->count == 0)))
1172 {
1173 do_match = 0;
1174 }
1175 else
1176 {
1177 qp = (mem_record_t **)calloc(query->count, sizeof(mem_record_t *));
1178 if (qp == NULL) return ASL_STATUS_NO_MEMORY;
1179
1180 qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t));
1181 if (qtype == NULL)
1182 {
1183 free(qp);
1184 return ASL_STATUS_NO_MEMORY;
1185 }
1186
1187 do_match = 0;
1188 for (i = 0; i < query->count; i++)
1189 {
1190 qp[i] = asl_memory_query_to_record(s, (aslmsg)query->msg[i], &(qtype[i]));
1191 if (qtype[i] == ASL_QUERY_MATCH_ERROR)
1192 {
1193 for (j = 0; j < i; j++) asl_memory_record_free(s, qp[j]);
1194 free(qp);
1195 free(qtype);
1196 return ASL_STATUS_FAILED;
1197 }
1198
1199 if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1;
1200 }
1201 }
1202
1203 for (i = 0; i < s->record_count; i++)
1204 {
1205 if (direction >= 0)
1206 {
1207 where = (s->record_first + i) % s->record_count;
1208 if (s->record[where]->mid == 0) continue;
1209 if (s->record[where]->mid >= start_id) break;
1210 }
1211 else
1212 {
1213 where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count;
1214 if (s->record[where]->mid == 0) continue;
1215 if (s->record[where]->mid <= start_id) break;
1216 }
1217 }
1218
1219 if (i >= s->record_count)
1220 {
1221 if (qp != NULL)
1222 {
1223 for (i = 0; i < query->count; i++) asl_memory_record_free(s, qp[i]);
1224 free(qp);
1225 free(qtype);
1226 }
1227
1228 return ASL_STATUS_OK;
1229 }
1230
1231 start = where;
1232
1233 /*
1234 * loop through records
1235 */
1236 for (i = 0; i < s->record_count; i++)
1237 {
1238 status = ASL_STATUS_INVALID_ID;
1239 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);
1240
1241 if ((status == ASL_STATUS_OK) && (uuid_str != NULL))
1242 {
1243 if (s->record[where]->sender_mach_uuid == NULL) status = ASL_STATUS_INVALID_ID;
1244 else if (strcmp(s->record[where]->sender_mach_uuid->str, uuid_str) != 0) status = ASL_STATUS_INVALID_ID;
1245 }
1246
1247 if (status != ASL_STATUS_OK)
1248 {
1249 if (direction >= 0)
1250 {
1251 where++;
1252 if (where >= s->record_count) where = 0;
1253 }
1254 else
1255 {
1256 if (where == 0) where = s->record_count - 1;
1257 else where--;
1258 }
1259
1260 if (where == s->record_first) break;
1261 continue;
1262 }
1263
1264 s->record[where]->flags &= ASL_MSG_FLAG_SEARCH_CLEAR;
1265 *last_id = s->record[where]->mid;
1266 did_match = 1;
1267
1268 if (do_match != 0)
1269 {
1270 did_match = 0;
1271
1272 for (j = 0; (j < query->count) && (did_match == 0); j++)
1273 {
1274 if (qtype[j] == ASL_QUERY_MATCH_TRUE)
1275 {
1276 did_match = 1;
1277 }
1278 else if (qtype[j] == ASL_QUERY_MATCH_FALSE)
1279 {
1280 did_match = 0;
1281 }
1282 else if (qtype[j] == ASL_QUERY_MATCH_SLOW)
1283 {
1284 did_match = asl_memory_slow_match(s, s->record[where], (aslmsg)query->msg[j]);
1285 }
1286 else
1287 {
1288 did_match = asl_memory_fast_match(s, s->record[where], qtype[j], qp[j]);
1289 }
1290 }
1291 }
1292
1293 if (did_match == 1)
1294 {
1295 s->record[where]->flags |= ASL_MSG_FLAG_SEARCH_MATCH;
1296 rescount++;
1297 if ((count != 0) && (rescount >= count)) break;
1298 }
1299
1300 if (direction >= 0)
1301 {
1302 where++;
1303 if (where >= s->record_count) where = 0;
1304 }
1305 else
1306 {
1307 if (where == 0) where = s->record_count - 1;
1308 else where--;
1309 }
1310
1311 if (where == s->record_first) break;
1312 }
1313
1314 if (query != NULL)
1315 {
1316 for (i = 0; i < query->count; i++) asl_memory_record_free(s, qp[i]);
1317 free(qp);
1318 free(qtype);
1319 }
1320
1321 *res = NULL;
1322 if (rescount == 0) return ASL_STATUS_OK;
1323
1324 *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
1325 if (*res == NULL) return ASL_STATUS_NO_MEMORY;
1326
1327 (*res)->count = rescount;
1328
1329 (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *));
1330 if ((*res)->msg == NULL)
1331 {
1332 free(*res);
1333 *res = NULL;
1334 return ASL_STATUS_NO_MEMORY;
1335 }
1336
1337 where = start;
1338 forever
1339 {
1340 if (s->record[where]->flags & ASL_MSG_FLAG_SEARCH_MATCH)
1341 {
1342 s->record[where]->flags &= ASL_MSG_FLAG_SEARCH_CLEAR;
1343
1344 status = asl_memory_message_decode(s, s->record[where], &m);
1345 if (status != ASL_STATUS_OK)
1346 {
1347 aslresponse_free(*res);
1348 *res = NULL;
1349 return status;
1350 }
1351
1352 (*res)->msg[(*res)->curr++] = (asl_msg_t *)m;
1353 if ((*res)->curr == rescount) break;
1354 }
1355
1356 if (direction >= 0)
1357 {
1358 where++;
1359 if (where >= s->record_count) where = 0;
1360 }
1361 else
1362 {
1363 if (where == 0) where = s->record_count - 1;
1364 else where--;
1365 }
1366
1367 if (where == s->record_first) break;
1368 }
1369
1370 (*res)->curr = 0;
1371 return ASL_STATUS_OK;
1372 }
1373
1374 uint32_t
1375 asl_memory_match(asl_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)
1376 {
1377 return asl_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, direction, ruid, rgid, NULL);
1378 }