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