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