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