2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/errno.h>
29 #include <sys/types.h>
33 #include <asl_msg_list.h>
34 #include <asl_private.h>
35 #include "asl_memory.h"
37 #define DEFAULT_MAX_RECORDS 2000
38 #define DEFAULT_MAX_STRING_MEMORY 4096000
40 #define forever for(;;)
43 asl_memory_statistics(asl_memory_t
*s
, asl_msg_t
**msg
)
50 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
51 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
53 out
= asl_msg_new(ASL_TYPE_MSG
);
54 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
56 size
= sizeof(asl_memory_t
);
57 size
+= ((s
->record_count
+ 1) * sizeof(mem_record_t
));
59 for (i
= 0; i
< s
->string_count
; i
++)
61 size
+= sizeof(mem_string_t
);
62 if (s
->string_cache
[i
]->str
!= NULL
) size
+= (strlen(s
->string_cache
[i
]->str
) + 1);
65 snprintf(str
, sizeof(str
), "%llu", size
);
66 asl_msg_set_key_val(out
, "Size", str
);
69 for (i
= 0; i
< s
->record_count
; i
++) if (s
->record
[i
]->mid
!= 0) n
++;
71 snprintf(str
, sizeof(str
), "%u", s
->record_count
);
72 asl_msg_set_key_val(out
, "MaxRecords", str
);
74 snprintf(str
, sizeof(str
), "%u", n
);
75 asl_msg_set_key_val(out
, "RecordCount", str
);
77 snprintf(str
, sizeof(str
), "%u", s
->string_count
);
78 asl_msg_set_key_val(out
, "StringCount", str
);
80 snprintf(str
, sizeof(str
), "%lu", s
->curr_string_mem
);
81 asl_msg_set_key_val(out
, "StringMemory", str
);
83 snprintf(str
, sizeof(str
), "%lu", s
->max_string_mem
);
84 asl_msg_set_key_val(out
, "MaxStringMemory", str
);
91 asl_memory_close(asl_memory_t
*s
)
93 if (s
== NULL
) return ASL_STATUS_OK
;
95 dispatch_sync(s
->queue
, ^{
98 if (s
->record
!= NULL
)
100 for (i
= 0; i
< s
->record_count
; i
++)
110 free(s
->buffer_record
);
111 s
->buffer_record
= NULL
;
113 if (s
->string_cache
!= NULL
)
115 for (i
= 0; i
< s
->string_count
; i
++)
117 if (s
->string_cache
[i
] != NULL
)
119 free(s
->string_cache
[i
]->str
);
120 free(s
->string_cache
[i
]);
123 s
->string_cache
[i
] = NULL
;
126 free(s
->string_cache
);
127 s
->string_cache
= NULL
;
131 dispatch_release(s
->queue
);
135 return ASL_STATUS_OK
;
139 asl_memory_open(uint32_t max_records
, size_t max_str_mem
, asl_memory_t
**s
)
144 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
146 if (max_records
== 0) max_records
= DEFAULT_MAX_RECORDS
;
147 if (max_str_mem
== 0) max_str_mem
= DEFAULT_MAX_STRING_MEMORY
;
149 out
= calloc(1, sizeof(asl_memory_t
));
150 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
152 out
->queue
= dispatch_queue_create("ASL Memory Queue", NULL
);
153 if (out
->queue
== NULL
)
156 return ASL_STATUS_NO_MEMORY
;
159 out
->max_string_mem
= max_str_mem
;
161 out
->record_count
= max_records
;
162 out
->record
= (mem_record_t
**)calloc(max_records
, sizeof(mem_record_t
*));
163 if (out
->record
== NULL
)
165 dispatch_release(out
->queue
);
167 return ASL_STATUS_NO_MEMORY
;
170 for (i
= 0; i
< max_records
; i
++)
172 out
->record
[i
] = (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
173 if (out
->record
[i
] == NULL
)
175 asl_memory_close(out
);
176 return ASL_STATUS_NO_MEMORY
;
180 out
->buffer_record
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
181 if (out
->buffer_record
== NULL
)
183 asl_memory_close(out
);
184 return ASL_STATUS_NO_MEMORY
;
188 return ASL_STATUS_OK
;
192 asl_memory_reset(asl_memory_t
*s
)
195 if (s
== NULL
) return;
197 /* clear all message records */
198 for (i
= 0; i
< s
->record_count
; i
++)
200 memset(s
->record
[i
], 0, sizeof(mem_record_t
));
203 /* reset the string cache */
204 if (s
->string_cache
!= NULL
)
206 for (i
= 0; i
< s
->string_count
; i
++)
208 if (s
->string_cache
[i
] != NULL
)
210 free(s
->string_cache
[i
]->str
);
211 free(s
->string_cache
[i
]);
214 s
->string_cache
[i
] = NULL
;
217 free(s
->string_cache
);
218 s
->string_cache
= NULL
;
224 static mem_string_t
*
225 asl_memory_string_new(const char *str
, uint32_t len
, uint32_t hash
)
229 if (str
== NULL
) return NULL
;
231 out
= (mem_string_t
*)calloc(1, sizeof(mem_string_t
));
232 if (out
== NULL
) return NULL
;
236 out
->str
= malloc(len
+ 1);
237 if (out
->str
== NULL
)
243 memcpy(out
->str
, str
, len
);
250 * Find the first hash greater than or equal to a given hash in the string cache.
251 * Return s->string_count if hash is greater than last hash in the string cache.
252 * Caller must check if the hashes match or not.
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.
258 asl_memory_string_cache_search_hash(asl_memory_t
*s
, uint32_t hash
)
260 uint32_t top
, bot
, mid
, range
;
263 if (s
->string_count
== 0) return 0;
264 if (s
->string_count
== 1)
266 ms
= s
->string_cache
[0];
267 if (hash
< ms
->hash
) return 0;
271 range
= top
= s
->string_count
- 1;
277 ms
= s
->string_cache
[mid
];
279 if (hash
== ms
->hash
)
283 ms
= s
->string_cache
[mid
- 1];
284 if (hash
!= ms
->hash
) break;
292 ms
= s
->string_cache
[mid
];
293 if (hash
< ms
->hash
) top
= mid
;
298 mid
= bot
+ (range
/ 2);
301 ms
= s
->string_cache
[bot
];
302 if (hash
<= ms
->hash
) return bot
;
304 ms
= s
->string_cache
[top
];
305 if (hash
<= ms
->hash
) return top
;
307 return s
->string_count
;
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.
316 static mem_string_t
*
317 asl_memory_string_retain(asl_memory_t
*s
, const char *str
, int create
)
319 uint32_t i
, where
, hash
, len
;
322 if (s
== NULL
) return NULL
;
323 if (str
== NULL
) return NULL
;
326 /* check the cache */
327 hash
= asl_core_string_hash(str
, len
);
328 where
= asl_memory_string_cache_search_hash(s
, hash
);
330 /* asl_memory_string_cache_search_hash just tells us where to look */
331 if (where
< s
->string_count
)
333 while (s
->string_cache
[where
]->hash
== hash
)
335 if (!strcmp(str
, s
->string_cache
[where
]->str
))
337 s
->string_cache
[where
]->refcount
++;
338 return s
->string_cache
[where
];
346 if (create
== 0) return NULL
;
348 /* create a new mem_string_t and insert into the cache at index 'where' */
349 new = asl_memory_string_new(str
, len
, hash
);
350 if (new == NULL
) return NULL
;
352 s
->string_cache
= (mem_string_t
**)reallocf(s
->string_cache
, (s
->string_count
+ 1) * sizeof(void *));
353 if (s
->string_cache
== NULL
)
360 for (i
= s
->string_count
; i
> where
; i
--) s
->string_cache
[i
] = s
->string_cache
[i
- 1];
362 s
->curr_string_mem
+= (sizeof(mem_string_t
) + len
+ 1);
363 s
->string_cache
[where
] = new;
366 return s
->string_cache
[where
];
370 asl_memory_string_release(asl_memory_t
*s
, mem_string_t
*m
)
374 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
375 if (m
== NULL
) return ASL_STATUS_OK
;
377 if (m
->refcount
> 0) m
->refcount
--;
378 if (m
->refcount
> 0) return ASL_STATUS_OK
;
380 where
= asl_memory_string_cache_search_hash(s
, m
->hash
);
381 if (s
->string_cache
[where
]->hash
!= m
->hash
) return ASL_STATUS_OK
;
383 while (s
->string_cache
[where
] != m
)
385 if (s
->string_cache
[where
]->hash
!= m
->hash
) return ASL_STATUS_OK
;
388 if (where
>= s
->string_count
) return ASL_STATUS_OK
;
391 for (i
= where
+ 1; i
< s
->string_count
; i
++) s
->string_cache
[i
- 1] = s
->string_cache
[i
];
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);
401 if (s
->string_count
== 0)
403 free(s
->string_cache
);
404 s
->string_cache
= NULL
;
405 return ASL_STATUS_OK
;
408 s
->string_cache
= (mem_string_t
**)reallocf(s
->string_cache
, s
->string_count
* sizeof(void *));
409 if (s
->string_cache
== NULL
)
412 return ASL_STATUS_NO_MEMORY
;
415 return ASL_STATUS_OK
;
419 * Release all a record's strings and reset it's values
422 asl_memory_record_clear(asl_memory_t
*s
, mem_record_t
*r
)
426 if (s
== NULL
) return;
427 if (r
== NULL
) return;
429 asl_memory_string_release(s
, r
->host
);
430 asl_memory_string_release(s
, r
->sender
);
431 asl_memory_string_release(s
, r
->sender_mach_uuid
);
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
);
437 for (i
= 0; i
< r
->kvcount
; i
++) asl_memory_string_release(s
, r
->kvlist
[i
]);
439 if (r
->kvlist
!= NULL
) free(r
->kvlist
);
440 memset(r
, 0, sizeof(mem_record_t
));
444 asl_memory_record_free(asl_memory_t
*s
, mem_record_t
*r
)
446 asl_memory_record_clear(s
, r
);
451 * Encode an asl_msg_t as a record structure.
452 * Creates and caches strings.
455 asl_memory_message_encode(asl_memory_t
*s
, asl_msg_t
*msg
)
460 const char *key
, *val
;
462 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
463 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
464 if (msg
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
466 r
= s
->buffer_record
;
468 memset(r
, 0, sizeof(mem_record_t
));
471 r
->level
= ASL_LEVEL_DEBUG
;
477 r
->time
= (uint64_t)-1;
478 r
->nano
= (uint32_t)-1;
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
))
485 if (key
== NULL
) continue;
487 else if (!strcmp(key
, ASL_KEY_TIME
))
489 if (val
!= NULL
) r
->time
= asl_core_parse_time(val
, NULL
);
491 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
493 if (val
!= NULL
) r
->nano
= atoi(val
);
495 else if (!strcmp(key
, ASL_KEY_HOST
))
497 if (val
!= NULL
) r
->host
= asl_memory_string_retain(s
, val
, 1);
499 else if (!strcmp(key
, ASL_KEY_SENDER
))
501 if (val
!= NULL
) r
->sender
= asl_memory_string_retain(s
, val
, 1);
503 else if (!strcmp(key
, ASL_KEY_PID
))
505 if (val
!= NULL
) r
->pid
= atoi(val
);
507 else if (!strcmp(key
, ASL_KEY_REF_PID
))
509 if (val
!= NULL
) r
->refpid
= atoi(val
);
511 else if (!strcmp(key
, ASL_KEY_UID
))
513 if (val
!= NULL
) r
->uid
= atoi(val
);
515 else if (!strcmp(key
, ASL_KEY_GID
))
517 if (val
!= NULL
) r
->gid
= atoi(val
);
519 else if (!strcmp(key
, ASL_KEY_LEVEL
))
521 if (val
!= NULL
) r
->level
= atoi(val
);
523 else if (!strcmp(key
, ASL_KEY_MSG
))
525 if (val
!= NULL
) r
->message
= asl_memory_string_retain(s
, val
, 1);
527 else if (!strcmp(key
, ASL_KEY_SENDER_MACH_UUID
))
529 if (val
!= NULL
) r
->sender_mach_uuid
= asl_memory_string_retain(s
, val
, 1);
531 else if (!strcmp(key
, ASL_KEY_FACILITY
))
533 if (val
!= NULL
) r
->facility
= asl_memory_string_retain(s
, val
, 1);
535 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
537 if (val
!= NULL
) r
->refproc
= asl_memory_string_retain(s
, val
, 1);
539 else if (!strcmp(key
, ASL_KEY_SESSION
))
541 if (val
!= NULL
) r
->session
= asl_memory_string_retain(s
, val
, 1);
543 else if (!strcmp(key
, ASL_KEY_READ_UID
))
545 if (((r
->flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (val
!= NULL
))
548 r
->flags
|= ASL_MSG_FLAG_READ_UID_SET
;
551 else if (!strcmp(key
, ASL_KEY_READ_GID
))
553 if (((r
->flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (val
!= NULL
))
556 r
->flags
|= ASL_MSG_FLAG_READ_GID_SET
;
559 else if (!strcmp(key
, ASL_KEY_OS_ACTIVITY_ID
))
561 if (val
!= NULL
) r
->os_activity_id
= atoll(val
);
563 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
570 k
= asl_memory_string_retain(s
, key
, 1);
571 if (k
== NULL
) continue;
574 if (val
!= NULL
) v
= asl_memory_string_retain(s
, val
, 1);
576 r
->kvlist
= (mem_string_t
**)reallocf(r
->kvlist
, (r
->kvcount
+ 2) * sizeof(mem_string_t
*));
577 if (r
->kvlist
== NULL
)
579 asl_memory_record_clear(s
, r
);
580 return ASL_STATUS_NO_MEMORY
;
583 r
->kvlist
[r
->kvcount
++] = k
;
584 r
->kvlist
[r
->kvcount
++] = v
;
588 return ASL_STATUS_OK
;
592 asl_memory_save(asl_memory_t
*s
, asl_msg_t
*msg
, uint64_t *mid
)
594 __block
uint32_t status
;
596 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
597 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
599 dispatch_sync(s
->queue
, ^{
602 /* asl_memory_message_encode creates and caches strings */
603 status
= asl_memory_message_encode(s
, msg
);
604 if (status
== ASL_STATUS_OK
)
606 uint32_t loop_start_index
= s
->record_first
;
610 s
->buffer_record
->mid
= *mid
;
614 s
->buffer_record
->mid
= asl_core_new_msg_id(0);
615 *mid
= s
->buffer_record
->mid
;
618 /* clear the first record */
619 t
= s
->record
[s
->record_first
];
620 asl_memory_record_clear(s
, t
);
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
;
626 /* record list is a circular queue */
628 if (s
->record_first
>= s
->record_count
) s
->record_first
= 0;
630 /* delete records if too much memory is in use */
631 while (s
->curr_string_mem
> s
->max_string_mem
)
633 asl_memory_record_clear(s
, s
->record
[s
->record_first
]);
635 if (s
->record_first
>= s
->record_count
) s
->record_first
= 0;
636 if (s
->record_first
== loop_start_index
)
638 /* The entire ring has been cleared. This should never happen. */
640 status
= ASL_STATUS_FAILED
;
651 * Decodes a record structure.
654 asl_memory_message_decode(asl_memory_t
*s
, mem_record_t
*r
, asl_msg_t
**out
)
659 const char *key
, *val
;
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
;
667 msg
= asl_msg_new(ASL_TYPE_MSG
);
668 if (msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
671 snprintf(tmp
, sizeof(tmp
), "%llu", r
->mid
);
672 asl_msg_set_key_val(msg
, ASL_KEY_MSG_ID
, tmp
);
675 snprintf(tmp
, sizeof(tmp
), "%u", r
->level
);
676 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, tmp
);
679 if (r
->time
!= (uint64_t)-1)
681 snprintf(tmp
, sizeof(tmp
), "%llu", r
->time
);
682 asl_msg_set_key_val(msg
, ASL_KEY_TIME
, tmp
);
686 if (r
->nano
!= (uint32_t)-1)
688 snprintf(tmp
, sizeof(tmp
), "%u", r
->nano
);
689 asl_msg_set_key_val(msg
, ASL_KEY_TIME_NSEC
, tmp
);
695 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, r
->host
->str
);
699 if (r
->sender
!= NULL
)
701 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, r
->sender
->str
);
704 /* Sender mach UUID */
705 if (r
->sender_mach_uuid
!= NULL
)
707 asl_msg_set_key_val(msg
, ASL_KEY_SENDER_MACH_UUID
, r
->sender_mach_uuid
->str
);
711 if (r
->facility
!= NULL
)
713 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, r
->facility
->str
);
717 if (r
->refproc
!= NULL
)
719 asl_msg_set_key_val(msg
, ASL_KEY_REF_PROC
, r
->refproc
->str
);
723 if (r
->session
!= NULL
)
725 asl_msg_set_key_val(msg
, ASL_KEY_SESSION
, r
->session
->str
);
731 snprintf(tmp
, sizeof(tmp
), "%d", r
->pid
);
732 asl_msg_set_key_val(msg
, ASL_KEY_PID
, tmp
);
738 snprintf(tmp
, sizeof(tmp
), "%d", r
->refpid
);
739 asl_msg_set_key_val(msg
, ASL_KEY_REF_PID
, tmp
);
745 snprintf(tmp
, sizeof(tmp
), "%d", r
->uid
);
746 asl_msg_set_key_val(msg
, ASL_KEY_UID
, tmp
);
752 snprintf(tmp
, sizeof(tmp
), "%d", r
->gid
);
753 asl_msg_set_key_val(msg
, ASL_KEY_GID
, tmp
);
757 if (r
->message
!= NULL
)
759 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, r
->message
->str
);
763 if (r
->flags
& ASL_MSG_FLAG_READ_UID_SET
)
765 snprintf(tmp
, sizeof(tmp
), "%d", r
->ruid
);
766 asl_msg_set_key_val(msg
, ASL_KEY_READ_UID
, tmp
);
770 if (r
->flags
& ASL_MSG_FLAG_READ_GID_SET
)
772 snprintf(tmp
, sizeof(tmp
), "%d", r
->rgid
);
773 asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, tmp
);
777 if (r
->os_activity_id
!= 0)
779 snprintf(tmp
, sizeof(tmp
), "%llu", r
->os_activity_id
);
780 asl_msg_set_key_val(msg
, ASL_KEY_OS_ACTIVITY_ID
, tmp
);
783 /* Key - Value List */
784 for (i
= 0; i
< r
->kvcount
; i
++)
789 if (r
->kvlist
[i
] != NULL
) key
= r
->kvlist
[i
]->str
;
791 if (r
->kvlist
[i
] != NULL
) val
= r
->kvlist
[i
]->str
;
793 if (key
!= NULL
) asl_msg_set_key_val(msg
, key
, val
);
797 return ASL_STATUS_OK
;
801 asl_memory_fetch(asl_memory_t
*s
, uint64_t mid
, asl_msg_t
**msg
, int32_t ruid
, int32_t rgid
)
803 __block
uint32_t status
;
805 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
806 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
808 status
= ASL_STATUS_INVALID_ID
;
810 dispatch_sync(s
->queue
, ^{
813 for (i
= 0; i
< s
->record_count
; i
++)
815 if (s
->record
[i
]->mid
== 0) break;
817 if (s
->record
[i
]->mid
== mid
)
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;
822 status
= asl_memory_message_decode(s
, s
->record
[i
], msg
);
831 static mem_record_t
*
832 asl_memory_query_to_record(asl_memory_t
*s
, asl_msg_t
*q
, uint32_t *type
)
837 mem_string_t
*mkey
, *mval
;
838 const char *key
, *val
;
840 if (type
== NULL
) return NULL
;
844 *type
= ASL_QUERY_MATCH_ERROR
;
848 /* NULL query matches anything */
849 *type
= ASL_QUERY_MATCH_TRUE
;
850 if (q
== NULL
) return NULL
;
851 if (asl_msg_count((asl_msg_t
*)q
) == 0) return NULL
;
854 /* we can only do fast match on equality tests */
855 *type
= ASL_QUERY_MATCH_SLOW
;
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
))
859 if (op
!= ASL_QUERY_OP_EQUAL
) return NULL
;
862 out
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
865 *type
= ASL_QUERY_MATCH_ERROR
;
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
))
871 if (key
== NULL
) continue;
873 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
875 if (val
== NULL
) continue;
877 if (*type
& ASL_QUERY_MATCH_MSG_ID
)
879 asl_memory_record_free(s
, out
);
880 *type
= ASL_QUERY_MATCH_SLOW
;
884 *type
|= ASL_QUERY_MATCH_MSG_ID
;
885 out
->mid
= atoll(val
);
887 else if (!strcmp(key
, ASL_KEY_TIME
))
889 if (val
== NULL
) continue;
891 if (*type
& ASL_QUERY_MATCH_TIME
)
893 asl_memory_record_free(s
, out
);
894 *type
= ASL_QUERY_MATCH_SLOW
;
898 *type
|= ASL_QUERY_MATCH_TIME
;
899 out
->time
= asl_core_parse_time(val
, NULL
);
901 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
903 if (val
== NULL
) continue;
905 if (*type
& ASL_QUERY_MATCH_NANO
)
907 asl_memory_record_free(s
, out
);
908 *type
= ASL_QUERY_MATCH_SLOW
;
912 *type
|= ASL_QUERY_MATCH_NANO
;
913 out
->nano
= atoll(val
);
915 else if (!strcmp(key
, ASL_KEY_LEVEL
))
917 if (val
== NULL
) continue;
919 if (*type
& ASL_QUERY_MATCH_LEVEL
)
921 asl_memory_record_free(s
, out
);
922 *type
= ASL_QUERY_MATCH_SLOW
;
926 *type
|= ASL_QUERY_MATCH_LEVEL
;
927 out
->level
= atoi(val
);
929 else if (!strcmp(key
, ASL_KEY_PID
))
931 if (val
== NULL
) continue;
933 if (*type
& ASL_QUERY_MATCH_PID
)
935 asl_memory_record_free(s
, out
);
936 *type
= ASL_QUERY_MATCH_SLOW
;
940 *type
|= ASL_QUERY_MATCH_PID
;
941 out
->pid
= atoi(val
);
943 else if (!strcmp(key
, ASL_KEY_UID
))
945 if (val
== NULL
) continue;
947 if (*type
& ASL_QUERY_MATCH_UID
)
949 asl_memory_record_free(s
, out
);
950 *type
= ASL_QUERY_MATCH_SLOW
;
954 *type
|= ASL_QUERY_MATCH_UID
;
955 out
->uid
= atoi(val
);
957 else if (!strcmp(key
, ASL_KEY_GID
))
959 if (val
== NULL
) continue;
961 if (*type
& ASL_QUERY_MATCH_GID
)
963 asl_memory_record_free(s
, out
);
964 *type
= ASL_QUERY_MATCH_SLOW
;
968 *type
|= ASL_QUERY_MATCH_GID
;
969 out
->gid
= atoi(val
);
971 else if (!strcmp(key
, ASL_KEY_READ_UID
))
973 if (val
== NULL
) continue;
975 if (*type
& ASL_QUERY_MATCH_RUID
)
977 asl_memory_record_free(s
, out
);
978 *type
= ASL_QUERY_MATCH_SLOW
;
982 *type
|= ASL_QUERY_MATCH_RUID
;
983 out
->ruid
= atoi(val
);
985 else if (!strcmp(key
, ASL_KEY_READ_GID
))
987 if (val
== NULL
) continue;
989 if (*type
& ASL_QUERY_MATCH_RGID
)
991 asl_memory_record_free(s
, out
);
992 *type
= ASL_QUERY_MATCH_SLOW
;
996 *type
|= ASL_QUERY_MATCH_RGID
;
997 out
->rgid
= atoi(val
);
999 else if (!strcmp(key
, ASL_KEY_REF_PID
))
1001 if (val
== NULL
) continue;
1003 if (*type
& ASL_QUERY_MATCH_REF_PID
)
1005 asl_memory_record_free(s
, out
);
1006 *type
= ASL_QUERY_MATCH_SLOW
;
1010 *type
|= ASL_QUERY_MATCH_REF_PID
;
1011 out
->refpid
= atoi(val
);
1013 else if (!strcmp(key
, ASL_KEY_HOST
))
1015 if (val
== NULL
) continue;
1017 if (*type
& ASL_QUERY_MATCH_HOST
)
1019 asl_memory_record_free(s
, out
);
1020 *type
= ASL_QUERY_MATCH_SLOW
;
1024 *type
|= ASL_QUERY_MATCH_HOST
;
1025 out
->host
= asl_memory_string_retain(s
, val
, 0);
1026 if (out
->host
== NULL
)
1028 asl_memory_record_free(s
, out
);
1029 *type
= ASL_QUERY_MATCH_FALSE
;
1033 else if (!strcmp(key
, ASL_KEY_SENDER
))
1035 if (val
== NULL
) continue;
1037 if (*type
& ASL_QUERY_MATCH_SENDER
)
1039 asl_memory_record_free(s
, out
);
1040 *type
= ASL_QUERY_MATCH_SLOW
;
1044 *type
|= ASL_QUERY_MATCH_SENDER
;
1045 out
->sender
= asl_memory_string_retain(s
, val
, 0);
1046 if (out
->sender
== NULL
)
1048 asl_memory_record_free(s
, out
);
1049 *type
= ASL_QUERY_MATCH_FALSE
;
1053 else if (!strcmp(key
, ASL_KEY_SENDER_MACH_UUID
))
1055 if (val
== NULL
) continue;
1057 if (*type
& ASL_QUERY_MATCH_SMUUID
)
1059 asl_memory_record_free(s
, out
);
1060 *type
= ASL_QUERY_MATCH_SLOW
;
1064 *type
|= ASL_QUERY_MATCH_SMUUID
;
1065 out
->sender
= asl_memory_string_retain(s
, val
, 0);
1066 if (out
->sender_mach_uuid
== NULL
)
1068 asl_memory_record_free(s
, out
);
1069 *type
= ASL_QUERY_MATCH_FALSE
;
1073 else if (!strcmp(key
, ASL_KEY_FACILITY
))
1075 if (val
== NULL
) continue;
1077 if (*type
& ASL_QUERY_MATCH_FACILITY
)
1079 asl_memory_record_free(s
, out
);
1080 *type
= ASL_QUERY_MATCH_SLOW
;
1084 *type
|= ASL_QUERY_MATCH_FACILITY
;
1085 out
->facility
= asl_memory_string_retain(s
, val
, 0);
1086 if (out
->facility
== NULL
)
1088 asl_memory_record_free(s
, out
);
1089 *type
= ASL_QUERY_MATCH_FALSE
;
1093 else if (!strcmp(key
, ASL_KEY_MSG
))
1095 if (val
== NULL
) continue;
1097 if (*type
& ASL_QUERY_MATCH_MESSAGE
)
1099 asl_memory_record_free(s
, out
);
1100 *type
= ASL_QUERY_MATCH_SLOW
;
1104 *type
|= ASL_QUERY_MATCH_MESSAGE
;
1105 out
->message
= asl_memory_string_retain(s
, val
, 0);
1106 if (out
->message
== NULL
)
1108 asl_memory_record_free(s
, out
);
1109 *type
= ASL_QUERY_MATCH_FALSE
;
1113 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
1115 if (val
== NULL
) continue;
1117 if (*type
& ASL_QUERY_MATCH_REF_PROC
)
1119 asl_memory_record_free(s
, out
);
1120 *type
= ASL_QUERY_MATCH_SLOW
;
1124 *type
|= ASL_QUERY_MATCH_REF_PROC
;
1125 out
->refproc
= asl_memory_string_retain(s
, val
, 0);
1126 if (out
->refproc
== NULL
)
1128 asl_memory_record_free(s
, out
);
1129 *type
= ASL_QUERY_MATCH_FALSE
;
1133 else if (!strcmp(key
, ASL_KEY_SESSION
))
1135 if (val
== NULL
) continue;
1137 if (*type
& ASL_QUERY_MATCH_SESSION
)
1139 asl_memory_record_free(s
, out
);
1140 *type
= ASL_QUERY_MATCH_SLOW
;
1144 *type
|= ASL_QUERY_MATCH_SESSION
;
1145 out
->session
= asl_memory_string_retain(s
, val
, 0);
1146 if (out
->session
== NULL
)
1148 asl_memory_record_free(s
, out
);
1149 *type
= ASL_QUERY_MATCH_FALSE
;
1155 mkey
= asl_memory_string_retain(s
, key
, 0);
1158 asl_memory_record_free(s
, out
);
1159 *type
= ASL_QUERY_MATCH_FALSE
;
1163 for (i
= 0; i
< out
->kvcount
; i
+= 2)
1165 if (out
->kvlist
[i
] == mkey
)
1167 asl_memory_record_free(s
, out
);
1168 *type
= ASL_QUERY_MATCH_SLOW
;
1173 mval
= asl_memory_string_retain(s
, val
, 0);
1175 if (out
->kvcount
== 0)
1177 out
->kvlist
= (mem_string_t
**)calloc(2, sizeof(mem_string_t
*));
1181 out
->kvlist
= (mem_string_t
**)reallocf(out
->kvlist
, (out
->kvcount
+ 2) * sizeof(mem_string_t
*));
1184 if (out
->kvlist
== NULL
)
1186 asl_memory_record_free(s
, out
);
1187 *type
= ASL_QUERY_MATCH_ERROR
;
1191 out
->kvlist
[out
->kvcount
++] = mkey
;
1192 out
->kvlist
[out
->kvcount
++] = mval
;
1200 asl_memory_fast_match(asl_memory_t
*s
, mem_record_t
*r
, uint32_t qtype
, mem_record_t
*q
)
1204 if (s
== NULL
) return 0;
1205 if (r
== NULL
) return 0;
1206 if (q
== NULL
) return 1;
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;
1220 if ((qtype
& ASL_QUERY_MATCH_SMUUID
) && (q
->sender_mach_uuid
!= r
->sender_mach_uuid
)) return 0;
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;
1226 for (i
= 0; i
< q
->kvcount
; i
+= 2)
1228 for (j
= 0; j
< r
->kvcount
; j
+= 2)
1230 if (q
->kvlist
[i
] == r
->kvlist
[j
])
1232 if (q
->kvlist
[i
+ 1] == r
->kvlist
[j
+ 1]) break;
1237 if (j
>= r
->kvcount
) return 0;
1244 asl_memory_slow_match(asl_memory_t
*s
, mem_record_t
*r
, asl_msg_t
*rawq
)
1250 status
= asl_memory_message_decode(s
, r
, &rawm
);
1251 if (status
!= ASL_STATUS_OK
) return 0;
1254 if (asl_msg_cmp((asl_msg_t
*)rawq
, (asl_msg_t
*)rawm
) != 0) status
= 1;
1255 asl_msg_release(rawm
);
1260 asl_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
)
1262 uint32_t status
, i
, where
, start
, j
, do_match
, did_match
, rescount
, *qtype
;
1266 struct timeval now
, finish
;
1271 qcount
= asl_msg_list_count(query
);
1279 qp
= (mem_record_t
**)calloc(qcount
, sizeof(mem_record_t
*));
1280 if (qp
== NULL
) return ASL_STATUS_NO_MEMORY
;
1282 qtype
= (uint32_t *)calloc(qcount
, sizeof(uint32_t));
1286 return ASL_STATUS_NO_MEMORY
;
1290 for (i
= 0; i
< qcount
; i
++)
1292 qp
[i
] = asl_memory_query_to_record(s
, asl_msg_list_get_index(query
, i
), &(qtype
[i
]));
1293 if (qtype
[i
] == ASL_QUERY_MATCH_ERROR
)
1295 for (j
= 0; j
< i
; j
++) asl_memory_record_free(s
, qp
[j
]);
1298 return ASL_STATUS_FAILED
;
1301 if (qtype
[i
] != ASL_QUERY_MATCH_TRUE
) do_match
= 1;
1305 for (i
= 0; i
< s
->record_count
; i
++)
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;
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;
1321 if (i
>= s
->record_count
)
1325 for (i
= 0; i
< qcount
; i
++) asl_memory_record_free(s
, qp
[i
]);
1330 return ASL_STATUS_OK
;
1333 /* start the timer if a duration was specified */
1334 memset(&finish
, 0, sizeof(struct timeval
));
1337 if (gettimeofday(&finish
, NULL
) == 0)
1339 finish
.tv_sec
+= (duration
/ USEC_PER_SEC
);
1340 finish
.tv_usec
+= (duration
% USEC_PER_SEC
);
1341 if (finish
.tv_usec
> USEC_PER_SEC
)
1343 finish
.tv_usec
-= USEC_PER_SEC
;
1349 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
1350 memset(&finish
, 0, sizeof(struct timeval
));
1357 * loop through records
1359 for (i
= 0; i
< s
->record_count
; i
++)
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
);
1364 if ((status
== ASL_STATUS_OK
) && (uuid_str
!= NULL
))
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
;
1370 if (status
!= ASL_STATUS_OK
)
1375 if (where
>= s
->record_count
) where
= 0;
1379 if (where
== 0) where
= s
->record_count
- 1;
1383 if (where
== s
->record_first
) break;
1387 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1388 *last_id
= s
->record
[where
]->mid
;
1395 for (j
= 0; (j
< qcount
) && (did_match
== 0); j
++)
1397 if (qtype
[j
] == ASL_QUERY_MATCH_TRUE
)
1401 else if (qtype
[j
] == ASL_QUERY_MATCH_FALSE
)
1405 else if (qtype
[j
] == ASL_QUERY_MATCH_SLOW
)
1407 did_match
= asl_memory_slow_match(s
, s
->record
[where
], asl_msg_list_get_index(query
, j
));
1411 did_match
= asl_memory_fast_match(s
, s
->record
[where
], qtype
[j
], qp
[j
]);
1418 s
->record
[where
]->flags
|= ASL_MSG_FLAG_SEARCH_MATCH
;
1420 if ((count
!= 0) && (rescount
>= count
)) break;
1423 /* check the timer */
1424 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
1426 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
1432 if (where
>= s
->record_count
) where
= 0;
1436 if (where
== 0) where
= s
->record_count
- 1;
1440 if (where
== s
->record_first
) break;
1445 for (i
= 0; i
< qcount
; i
++) asl_memory_record_free(s
, qp
[i
]);
1451 if (rescount
== 0) return ASL_STATUS_OK
;
1453 *res
= asl_msg_list_new();
1454 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1461 if (s
->record
[where
]->flags
& ASL_MSG_FLAG_SEARCH_MATCH
)
1463 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1465 status
= asl_memory_message_decode(s
, s
->record
[where
], &m
);
1466 if (status
!= ASL_STATUS_OK
)
1468 asl_msg_list_release(*res
);
1473 asl_msg_list_append(*res
, m
);
1476 if (n
== rescount
) break;
1482 if (where
>= s
->record_count
) where
= 0;
1486 if (where
== 0) where
= s
->record_count
- 1;
1490 if (where
== s
->record_first
) break;
1493 return ASL_STATUS_OK
;
1497 asl_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
)
1499 __block
uint32_t status
;
1501 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1502 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
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
);
1512 asl_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
)
1514 __block
uint32_t status
;
1516 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1517 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
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
);