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
39 #define MEM_STRING_HEADER_SIZE 8
41 #define forever for(;;)
44 asl_memory_statistics(asl_memory_t
*s
, asl_msg_t
**msg
)
51 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
52 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
54 out
= asl_msg_new(ASL_TYPE_MSG
);
55 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
57 size
= sizeof(asl_memory_t
);
58 size
+= ((s
->record_count
+ 1) * sizeof(mem_record_t
));
60 for (i
= 0; i
< s
->string_count
; i
++)
62 size
+= MEM_STRING_HEADER_SIZE
;
63 if (((mem_string_t
*)s
->string_cache
[i
])->str
!= NULL
) size
+= (strlen(((mem_string_t
*)s
->string_cache
[i
])->str
) + 1);
66 snprintf(str
, sizeof(str
), "%llu", size
);
67 asl_msg_set_key_val(out
, "Size", str
);
70 for (i
= 0; i
< s
->record_count
; i
++) if (s
->record
[i
]->mid
!= 0) n
++;
72 snprintf(str
, sizeof(str
), "%u", s
->record_count
);
73 asl_msg_set_key_val(out
, "MaxRecords", str
);
75 snprintf(str
, sizeof(str
), "%u", n
);
76 asl_msg_set_key_val(out
, "RecordCount", str
);
78 snprintf(str
, sizeof(str
), "%u", s
->string_count
);
79 asl_msg_set_key_val(out
, "StringCount", str
);
81 snprintf(str
, sizeof(str
), "%u", s
->curr_string_mem
);
82 asl_msg_set_key_val(out
, "StringMemory", str
);
84 snprintf(str
, sizeof(str
), "%u", s
->max_string_mem
);
85 asl_msg_set_key_val(out
, "MaxStringMemory", str
);
92 asl_memory_close(asl_memory_t
*s
)
96 if (s
== NULL
) return ASL_STATUS_OK
;
98 if (s
->record
!= NULL
)
100 for (i
= 0; i
< s
->record_count
; i
++)
102 if (s
->record
[i
] != NULL
) free(s
->record
[i
]);
110 if (s
->buffer_record
!= NULL
) free(s
->buffer_record
);
112 if (s
->string_cache
!= NULL
)
114 for (i
= 0; i
< s
->string_count
; i
++)
116 if (s
->string_cache
[i
] != NULL
) free(s
->string_cache
[i
]);
117 s
->string_cache
[i
] = NULL
;
120 free(s
->string_cache
);
121 s
->string_cache
= NULL
;
126 return ASL_STATUS_OK
;
130 asl_memory_open(uint32_t max_records
, size_t max_str_mem
, asl_memory_t
**s
)
135 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
137 if (max_records
== 0) max_records
= DEFAULT_MAX_RECORDS
;
138 if (max_str_mem
== 0) max_str_mem
= DEFAULT_MAX_STRING_MEMORY
;
140 out
= calloc(1, sizeof(asl_memory_t
));
141 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
143 out
->max_string_mem
= max_str_mem
;
145 out
->record_count
= max_records
;
146 out
->record
= (mem_record_t
**)calloc(max_records
, sizeof(mem_record_t
*));
147 if (out
->record
== NULL
)
150 return ASL_STATUS_NO_MEMORY
;
153 for (i
= 0; i
< max_records
; i
++)
155 out
->record
[i
] = (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
156 if (out
->record
[i
] == NULL
)
158 asl_memory_close(out
);
159 return ASL_STATUS_NO_MEMORY
;
163 out
->buffer_record
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
164 if (out
->buffer_record
== NULL
)
166 asl_memory_close(out
);
167 return ASL_STATUS_NO_MEMORY
;
171 return ASL_STATUS_OK
;
174 static mem_string_t
*
175 mem_string_new(const char *str
, uint32_t len
, uint32_t hash
)
180 if (str
== NULL
) return NULL
;
182 ss
= MEM_STRING_HEADER_SIZE
+ len
+ 1;
183 out
= (mem_string_t
*)calloc(1, ss
);
184 if (out
== NULL
) return NULL
;
188 memcpy(out
->str
, str
, len
);
194 * Find the first hash greater than or equal to a given hash in the string cache.
195 * Return s->string_count if hash is greater that or equal to last hash in the string cache.
196 * Caller must check if the hashes match or not.
198 * This routine is used both to find strings in the cache and to determine where to insert
199 * new strings. Note that the caller needs to do extra work after calling this routine.
202 asl_memory_string_cache_search_hash(asl_memory_t
*s
, uint32_t hash
)
204 uint32_t top
, bot
, mid
, range
;
207 if (s
->string_count
== 0) return 0;
208 if (s
->string_count
== 1)
210 ms
= (mem_string_t
*)s
->string_cache
[0];
211 if (hash
< ms
->hash
) return 0;
215 range
= top
= s
->string_count
- 1;
221 ms
= (mem_string_t
*)s
->string_cache
[mid
];
223 if (hash
== ms
->hash
)
227 ms
= (mem_string_t
*)s
->string_cache
[mid
- 1];
228 if (hash
!= ms
->hash
) break;
236 ms
= (mem_string_t
*)s
->string_cache
[mid
];
237 if (hash
< ms
->hash
) top
= mid
;
242 mid
= bot
+ (range
/ 2);
245 ms
= (mem_string_t
*)s
->string_cache
[bot
];
246 if (hash
<= ms
->hash
) return bot
;
248 ms
= (mem_string_t
*)s
->string_cache
[top
];
249 if (hash
<= ms
->hash
) return top
;
251 return s
->string_count
;
255 * Search the string cache.
256 * If the string is in the cache, increment refcount and return it.
257 * If the string is not in cache and create flag is on, create a new string.
258 * Otherwise, return NULL.
260 static mem_string_t
*
261 asl_memory_string_retain(asl_memory_t
*s
, const char *str
, int create
)
263 uint32_t i
, where
, hash
, len
;
266 if (s
== NULL
) return NULL
;
267 if (str
== NULL
) return NULL
;
270 /* check the cache */
271 hash
= asl_core_string_hash(str
, len
);
272 where
= asl_memory_string_cache_search_hash(s
, hash
);
274 /* asl_memory_string_cache_search_hash just tells us where to look */
275 if (where
< s
->string_count
)
277 while (((mem_string_t
*)(s
->string_cache
[where
]))->hash
== hash
)
279 if (!strcmp(str
, ((mem_string_t
*)(s
->string_cache
[where
]))->str
))
281 ((mem_string_t
*)(s
->string_cache
[where
]))->refcount
++;
282 return s
->string_cache
[where
];
290 if (create
== 0) return NULL
;
292 /* create a new mem_string_t and insert into the cache at index 'where' */
293 if (s
->string_count
== 0)
295 s
->string_cache
= (void **)calloc(1, sizeof(void *));
299 s
->string_cache
= (void **)reallocf(s
->string_cache
, (s
->string_count
+ 1) * sizeof(void *));
300 for (i
= s
->string_count
; i
> where
; i
--) s
->string_cache
[i
] = s
->string_cache
[i
- 1];
303 if (s
->string_cache
== NULL
)
309 new = mem_string_new(str
, len
, hash
);
310 if (new == NULL
) return NULL
;
312 s
->curr_string_mem
+= (MEM_STRING_HEADER_SIZE
+ len
+ 1);
313 s
->string_cache
[where
] = new;
316 return s
->string_cache
[where
];
320 asl_memory_string_release(asl_memory_t
*s
, mem_string_t
*m
)
324 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
325 if (m
== NULL
) return ASL_STATUS_OK
;
327 if (m
->refcount
> 0) m
->refcount
--;
328 if (m
->refcount
> 0) return ASL_STATUS_OK
;
330 where
= asl_memory_string_cache_search_hash(s
, m
->hash
);
331 if (((mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
333 while (s
->string_cache
[where
] != m
)
335 if (((mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
338 if (where
>= s
->string_count
) return ASL_STATUS_OK
;
341 for (i
= where
+ 1; i
< s
->string_count
; i
++) s
->string_cache
[i
- 1] = s
->string_cache
[i
];
343 s
->curr_string_mem
-= (MEM_STRING_HEADER_SIZE
+ strlen(m
->str
) + 1);
348 if (s
->string_count
== 0)
350 free(s
->string_cache
);
351 s
->string_cache
= NULL
;
352 return ASL_STATUS_OK
;
355 s
->string_cache
= (void **)reallocf(s
->string_cache
, s
->string_count
* sizeof(void *));
356 if (s
->string_cache
== NULL
)
359 return ASL_STATUS_NO_MEMORY
;
362 return ASL_STATUS_OK
;
366 * Release all a record's strings and reset it's values
369 asl_memory_record_clear(asl_memory_t
*s
, mem_record_t
*r
)
373 if (s
== NULL
) return;
374 if (r
== NULL
) return;
376 asl_memory_string_release(s
, r
->host
);
377 asl_memory_string_release(s
, r
->sender
);
378 asl_memory_string_release(s
, r
->sender_mach_uuid
);
379 asl_memory_string_release(s
, r
->facility
);
380 asl_memory_string_release(s
, r
->message
);
381 asl_memory_string_release(s
, r
->refproc
);
382 asl_memory_string_release(s
, r
->session
);
384 for (i
= 0; i
< r
->kvcount
; i
++) asl_memory_string_release(s
, r
->kvlist
[i
]);
386 if (r
->kvlist
!= NULL
) free(r
->kvlist
);
387 memset(r
, 0, sizeof(mem_record_t
));
391 asl_memory_record_free(asl_memory_t
*s
, mem_record_t
*r
)
393 asl_memory_record_clear(s
, r
);
398 * Encode an asl_msg_t as a record structure.
399 * Creates and caches strings.
402 asl_memory_message_encode(asl_memory_t
*s
, asl_msg_t
*msg
)
407 const char *key
, *val
;
409 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
410 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
411 if (msg
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
413 r
= s
->buffer_record
;
415 memset(r
, 0, sizeof(mem_record_t
));
418 r
->level
= ASL_LEVEL_DEBUG
;
424 r
->time
= (uint64_t)-1;
425 r
->nano
= (uint32_t)-1;
430 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
))
432 if (key
== NULL
) continue;
434 else if (!strcmp(key
, ASL_KEY_TIME
))
436 if (val
!= NULL
) r
->time
= asl_core_parse_time(val
, NULL
);
438 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
440 if (val
!= NULL
) r
->nano
= atoi(val
);
442 else if (!strcmp(key
, ASL_KEY_HOST
))
444 if (val
!= NULL
) r
->host
= asl_memory_string_retain(s
, val
, 1);
446 else if (!strcmp(key
, ASL_KEY_SENDER
))
448 if (val
!= NULL
) r
->sender
= asl_memory_string_retain(s
, val
, 1);
450 else if (!strcmp(key
, ASL_KEY_PID
))
452 if (val
!= NULL
) r
->pid
= atoi(val
);
454 else if (!strcmp(key
, ASL_KEY_REF_PID
))
456 if (val
!= NULL
) r
->refpid
= atoi(val
);
458 else if (!strcmp(key
, ASL_KEY_UID
))
460 if (val
!= NULL
) r
->uid
= atoi(val
);
462 else if (!strcmp(key
, ASL_KEY_GID
))
464 if (val
!= NULL
) r
->gid
= atoi(val
);
466 else if (!strcmp(key
, ASL_KEY_LEVEL
))
468 if (val
!= NULL
) r
->level
= atoi(val
);
470 else if (!strcmp(key
, ASL_KEY_MSG
))
472 if (val
!= NULL
) r
->message
= asl_memory_string_retain(s
, val
, 1);
474 else if (!strcmp(key
, ASL_KEY_SENDER_MACH_UUID
))
476 if (val
!= NULL
) r
->sender_mach_uuid
= asl_memory_string_retain(s
, val
, 1);
478 else if (!strcmp(key
, ASL_KEY_FACILITY
))
480 if (val
!= NULL
) r
->facility
= asl_memory_string_retain(s
, val
, 1);
482 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
484 if (val
!= NULL
) r
->refproc
= asl_memory_string_retain(s
, val
, 1);
486 else if (!strcmp(key
, ASL_KEY_SESSION
))
488 if (val
!= NULL
) r
->session
= asl_memory_string_retain(s
, val
, 1);
490 else if (!strcmp(key
, ASL_KEY_READ_UID
))
492 if (((r
->flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (val
!= NULL
))
495 r
->flags
|= ASL_MSG_FLAG_READ_UID_SET
;
498 else if (!strcmp(key
, ASL_KEY_READ_GID
))
500 if (((r
->flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (val
!= NULL
))
503 r
->flags
|= ASL_MSG_FLAG_READ_GID_SET
;
506 else if (!strcmp(key
, ASL_KEY_OS_ACTIVITY_ID
))
508 if (val
!= NULL
) r
->os_activity_id
= atoll(val
);
510 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
517 k
= asl_memory_string_retain(s
, key
, 1);
518 if (k
== NULL
) continue;
521 if (val
!= NULL
) v
= asl_memory_string_retain(s
, val
, 1);
525 r
->kvlist
= (mem_string_t
**)calloc(2, sizeof(mem_string_t
*));
529 r
->kvlist
= (mem_string_t
**)reallocf(r
->kvlist
, (r
->kvcount
+ 2) * sizeof(mem_string_t
*));
532 if (r
->kvlist
== NULL
)
534 asl_memory_record_clear(s
, r
);
535 return ASL_STATUS_NO_MEMORY
;
538 r
->kvlist
[r
->kvcount
++] = k
;
539 r
->kvlist
[r
->kvcount
++] = v
;
543 return ASL_STATUS_OK
;
547 asl_memory_save(asl_memory_t
*s
, asl_msg_t
*msg
, uint64_t *mid
)
552 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
553 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
555 /* asl_memory_message_encode creates and caches strings */
556 status
= asl_memory_message_encode(s
, msg
);
557 if (status
!= ASL_STATUS_OK
) return status
;
561 s
->buffer_record
->mid
= *mid
;
565 s
->buffer_record
->mid
= asl_core_new_msg_id(0);
566 *mid
= s
->buffer_record
->mid
;
569 /* clear the first record */
570 t
= s
->record
[s
->record_first
];
571 asl_memory_record_clear(s
, t
);
573 /* add the new record to the record list (swap in the buffer record) */
574 s
->record
[s
->record_first
] = s
->buffer_record
;
575 s
->buffer_record
= t
;
577 /* record list is a circular queue */
579 if (s
->record_first
>= s
->record_count
) s
->record_first
= 0;
581 /* delete records if too much memory is in use */
582 while (s
->curr_string_mem
> s
->max_string_mem
)
584 asl_memory_record_clear(s
, s
->record
[s
->record_first
]);
586 if (s
->record_first
>= s
->record_count
) s
->record_first
= 0;
593 * Decodes a record structure.
596 asl_memory_message_decode(asl_memory_t
*s
, mem_record_t
*r
, asl_msg_t
**out
)
601 const char *key
, *val
;
603 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
604 if (r
== NULL
) return ASL_STATUS_INVALID_ARG
;
605 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
609 msg
= asl_msg_new(ASL_TYPE_MSG
);
610 if (msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
613 snprintf(tmp
, sizeof(tmp
), "%llu", r
->mid
);
614 asl_msg_set_key_val(msg
, ASL_KEY_MSG_ID
, tmp
);
617 snprintf(tmp
, sizeof(tmp
), "%u", r
->level
);
618 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, tmp
);
621 if (r
->time
!= (uint64_t)-1)
623 snprintf(tmp
, sizeof(tmp
), "%llu", r
->time
);
624 asl_msg_set_key_val(msg
, ASL_KEY_TIME
, tmp
);
628 if (r
->nano
!= (uint32_t)-1)
630 snprintf(tmp
, sizeof(tmp
), "%u", r
->nano
);
631 asl_msg_set_key_val(msg
, ASL_KEY_TIME_NSEC
, tmp
);
637 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, r
->host
->str
);
641 if (r
->sender
!= NULL
)
643 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, r
->sender
->str
);
646 /* Sender mach UUID */
647 if (r
->sender_mach_uuid
!= NULL
)
649 asl_msg_set_key_val(msg
, ASL_KEY_SENDER_MACH_UUID
, r
->sender_mach_uuid
->str
);
653 if (r
->facility
!= NULL
)
655 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, r
->facility
->str
);
659 if (r
->refproc
!= NULL
)
661 asl_msg_set_key_val(msg
, ASL_KEY_REF_PROC
, r
->refproc
->str
);
665 if (r
->session
!= NULL
)
667 asl_msg_set_key_val(msg
, ASL_KEY_SESSION
, r
->session
->str
);
673 snprintf(tmp
, sizeof(tmp
), "%d", r
->pid
);
674 asl_msg_set_key_val(msg
, ASL_KEY_PID
, tmp
);
680 snprintf(tmp
, sizeof(tmp
), "%d", r
->refpid
);
681 asl_msg_set_key_val(msg
, ASL_KEY_REF_PID
, tmp
);
687 snprintf(tmp
, sizeof(tmp
), "%d", r
->uid
);
688 asl_msg_set_key_val(msg
, ASL_KEY_UID
, tmp
);
694 snprintf(tmp
, sizeof(tmp
), "%d", r
->gid
);
695 asl_msg_set_key_val(msg
, ASL_KEY_GID
, tmp
);
699 if (r
->message
!= NULL
)
701 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, r
->message
->str
);
705 if (r
->flags
& ASL_MSG_FLAG_READ_UID_SET
)
707 snprintf(tmp
, sizeof(tmp
), "%d", r
->ruid
);
708 asl_msg_set_key_val(msg
, ASL_KEY_READ_UID
, tmp
);
712 if (r
->flags
& ASL_MSG_FLAG_READ_GID_SET
)
714 snprintf(tmp
, sizeof(tmp
), "%d", r
->rgid
);
715 asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, tmp
);
719 if (r
->os_activity_id
!= 0)
721 snprintf(tmp
, sizeof(tmp
), "%llu", r
->os_activity_id
);
722 asl_msg_set_key_val(msg
, ASL_KEY_OS_ACTIVITY_ID
, tmp
);
725 /* Key - Value List */
726 for (i
= 0; i
< r
->kvcount
; i
++)
731 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) key
= r
->kvlist
[i
]->str
;
733 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) val
= r
->kvlist
[i
]->str
;
735 if (key
!= NULL
) asl_msg_set_key_val(msg
, key
, val
);
739 return ASL_STATUS_OK
;
743 asl_memory_fetch(asl_memory_t
*s
, uint64_t mid
, asl_msg_t
**msg
, int32_t ruid
, int32_t rgid
)
747 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
748 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
750 for (i
= 0; i
< s
->record_count
; i
++)
752 if (s
->record
[i
]->mid
== 0) break;
754 if (s
->record
[i
]->mid
== mid
)
756 status
= asl_core_check_access(s
->record
[i
]->ruid
, s
->record
[i
]->rgid
, ruid
, rgid
, s
->record
[i
]->flags
);
757 if (status
!= ASL_STATUS_OK
) return status
;
758 return asl_memory_message_decode(s
, s
->record
[i
], msg
);
762 return ASL_STATUS_INVALID_ID
;
765 static mem_record_t
*
766 asl_memory_query_to_record(asl_memory_t
*s
, asl_msg_t
*q
, uint32_t *type
)
771 mem_string_t
*mkey
, *mval
;
772 const char *key
, *val
;
774 if (type
== NULL
) return NULL
;
778 *type
= ASL_QUERY_MATCH_ERROR
;
782 /* NULL query matches anything */
783 *type
= ASL_QUERY_MATCH_TRUE
;
784 if (q
== NULL
) return NULL
;
785 if (asl_msg_count((asl_msg_t
*)q
) == 0) return NULL
;
788 /* we can only do fast match on equality tests */
789 *type
= ASL_QUERY_MATCH_SLOW
;
791 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
))
793 if (op
!= ASL_QUERY_OP_EQUAL
) return NULL
;
796 out
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
799 *type
= ASL_QUERY_MATCH_ERROR
;
803 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
))
805 if (key
== NULL
) continue;
807 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
809 if (val
== NULL
) continue;
811 if (*type
& ASL_QUERY_MATCH_MSG_ID
)
813 asl_memory_record_free(s
, out
);
814 *type
= ASL_QUERY_MATCH_SLOW
;
818 *type
|= ASL_QUERY_MATCH_MSG_ID
;
819 out
->mid
= atoll(val
);
821 else if (!strcmp(key
, ASL_KEY_TIME
))
823 if (val
== NULL
) continue;
825 if (*type
& ASL_QUERY_MATCH_TIME
)
827 asl_memory_record_free(s
, out
);
828 *type
= ASL_QUERY_MATCH_SLOW
;
832 *type
|= ASL_QUERY_MATCH_TIME
;
833 out
->time
= asl_core_parse_time(val
, NULL
);
835 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
837 if (val
== NULL
) continue;
839 if (*type
& ASL_QUERY_MATCH_NANO
)
841 asl_memory_record_free(s
, out
);
842 *type
= ASL_QUERY_MATCH_SLOW
;
846 *type
|= ASL_QUERY_MATCH_NANO
;
847 out
->nano
= atoll(val
);
849 else if (!strcmp(key
, ASL_KEY_LEVEL
))
851 if (val
== NULL
) continue;
853 if (*type
& ASL_QUERY_MATCH_LEVEL
)
855 asl_memory_record_free(s
, out
);
856 *type
= ASL_QUERY_MATCH_SLOW
;
860 *type
|= ASL_QUERY_MATCH_LEVEL
;
861 out
->level
= atoi(val
);
863 else if (!strcmp(key
, ASL_KEY_PID
))
865 if (val
== NULL
) continue;
867 if (*type
& ASL_QUERY_MATCH_PID
)
869 asl_memory_record_free(s
, out
);
870 *type
= ASL_QUERY_MATCH_SLOW
;
874 *type
|= ASL_QUERY_MATCH_PID
;
875 out
->pid
= atoi(val
);
877 else if (!strcmp(key
, ASL_KEY_UID
))
879 if (val
== NULL
) continue;
881 if (*type
& ASL_QUERY_MATCH_UID
)
883 asl_memory_record_free(s
, out
);
884 *type
= ASL_QUERY_MATCH_SLOW
;
888 *type
|= ASL_QUERY_MATCH_UID
;
889 out
->uid
= atoi(val
);
891 else if (!strcmp(key
, ASL_KEY_GID
))
893 if (val
== NULL
) continue;
895 if (*type
& ASL_QUERY_MATCH_GID
)
897 asl_memory_record_free(s
, out
);
898 *type
= ASL_QUERY_MATCH_SLOW
;
902 *type
|= ASL_QUERY_MATCH_GID
;
903 out
->gid
= atoi(val
);
905 else if (!strcmp(key
, ASL_KEY_READ_UID
))
907 if (val
== NULL
) continue;
909 if (*type
& ASL_QUERY_MATCH_RUID
)
911 asl_memory_record_free(s
, out
);
912 *type
= ASL_QUERY_MATCH_SLOW
;
916 *type
|= ASL_QUERY_MATCH_RUID
;
917 out
->ruid
= atoi(val
);
919 else if (!strcmp(key
, ASL_KEY_READ_GID
))
921 if (val
== NULL
) continue;
923 if (*type
& ASL_QUERY_MATCH_RGID
)
925 asl_memory_record_free(s
, out
);
926 *type
= ASL_QUERY_MATCH_SLOW
;
930 *type
|= ASL_QUERY_MATCH_RGID
;
931 out
->rgid
= atoi(val
);
933 else if (!strcmp(key
, ASL_KEY_REF_PID
))
935 if (val
== NULL
) continue;
937 if (*type
& ASL_QUERY_MATCH_REF_PID
)
939 asl_memory_record_free(s
, out
);
940 *type
= ASL_QUERY_MATCH_SLOW
;
944 *type
|= ASL_QUERY_MATCH_REF_PID
;
945 out
->refpid
= atoi(val
);
947 else if (!strcmp(key
, ASL_KEY_HOST
))
949 if (val
== NULL
) continue;
951 if (*type
& ASL_QUERY_MATCH_HOST
)
953 asl_memory_record_free(s
, out
);
954 *type
= ASL_QUERY_MATCH_SLOW
;
958 *type
|= ASL_QUERY_MATCH_HOST
;
959 out
->host
= asl_memory_string_retain(s
, val
, 0);
960 if (out
->host
== NULL
)
962 asl_memory_record_free(s
, out
);
963 *type
= ASL_QUERY_MATCH_FALSE
;
967 else if (!strcmp(key
, ASL_KEY_SENDER
))
969 if (val
== NULL
) continue;
971 if (*type
& ASL_QUERY_MATCH_SENDER
)
973 asl_memory_record_free(s
, out
);
974 *type
= ASL_QUERY_MATCH_SLOW
;
978 *type
|= ASL_QUERY_MATCH_SENDER
;
979 out
->sender
= asl_memory_string_retain(s
, val
, 0);
980 if (out
->sender
== NULL
)
982 asl_memory_record_free(s
, out
);
983 *type
= ASL_QUERY_MATCH_FALSE
;
987 else if (!strcmp(key
, ASL_KEY_SENDER_MACH_UUID
))
989 if (val
== NULL
) continue;
991 if (*type
& ASL_QUERY_MATCH_SMUUID
)
993 asl_memory_record_free(s
, out
);
994 *type
= ASL_QUERY_MATCH_SLOW
;
998 *type
|= ASL_QUERY_MATCH_SMUUID
;
999 out
->sender
= asl_memory_string_retain(s
, val
, 0);
1000 if (out
->sender_mach_uuid
== NULL
)
1002 asl_memory_record_free(s
, out
);
1003 *type
= ASL_QUERY_MATCH_FALSE
;
1007 else if (!strcmp(key
, ASL_KEY_FACILITY
))
1009 if (val
== NULL
) continue;
1011 if (*type
& ASL_QUERY_MATCH_FACILITY
)
1013 asl_memory_record_free(s
, out
);
1014 *type
= ASL_QUERY_MATCH_SLOW
;
1018 *type
|= ASL_QUERY_MATCH_FACILITY
;
1019 out
->facility
= asl_memory_string_retain(s
, val
, 0);
1020 if (out
->facility
== NULL
)
1022 asl_memory_record_free(s
, out
);
1023 *type
= ASL_QUERY_MATCH_FALSE
;
1027 else if (!strcmp(key
, ASL_KEY_MSG
))
1029 if (val
== NULL
) continue;
1031 if (*type
& ASL_QUERY_MATCH_MESSAGE
)
1033 asl_memory_record_free(s
, out
);
1034 *type
= ASL_QUERY_MATCH_SLOW
;
1038 *type
|= ASL_QUERY_MATCH_MESSAGE
;
1039 out
->message
= asl_memory_string_retain(s
, val
, 0);
1040 if (out
->message
== NULL
)
1042 asl_memory_record_free(s
, out
);
1043 *type
= ASL_QUERY_MATCH_FALSE
;
1047 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
1049 if (val
== NULL
) continue;
1051 if (*type
& ASL_QUERY_MATCH_REF_PROC
)
1053 asl_memory_record_free(s
, out
);
1054 *type
= ASL_QUERY_MATCH_SLOW
;
1058 *type
|= ASL_QUERY_MATCH_REF_PROC
;
1059 out
->refproc
= asl_memory_string_retain(s
, val
, 0);
1060 if (out
->refproc
== NULL
)
1062 asl_memory_record_free(s
, out
);
1063 *type
= ASL_QUERY_MATCH_FALSE
;
1067 else if (!strcmp(key
, ASL_KEY_SESSION
))
1069 if (val
== NULL
) continue;
1071 if (*type
& ASL_QUERY_MATCH_SESSION
)
1073 asl_memory_record_free(s
, out
);
1074 *type
= ASL_QUERY_MATCH_SLOW
;
1078 *type
|= ASL_QUERY_MATCH_SESSION
;
1079 out
->session
= asl_memory_string_retain(s
, val
, 0);
1080 if (out
->session
== NULL
)
1082 asl_memory_record_free(s
, out
);
1083 *type
= ASL_QUERY_MATCH_FALSE
;
1089 mkey
= asl_memory_string_retain(s
, key
, 0);
1092 asl_memory_record_free(s
, out
);
1093 *type
= ASL_QUERY_MATCH_FALSE
;
1097 for (i
= 0; i
< out
->kvcount
; i
+= 2)
1099 if (out
->kvlist
[i
] == mkey
)
1101 asl_memory_record_free(s
, out
);
1102 *type
= ASL_QUERY_MATCH_SLOW
;
1107 mval
= asl_memory_string_retain(s
, val
, 0);
1109 if (out
->kvcount
== 0)
1111 out
->kvlist
= (mem_string_t
**)calloc(2, sizeof(mem_string_t
*));
1115 out
->kvlist
= (mem_string_t
**)reallocf(out
->kvlist
, (out
->kvcount
+ 2) * sizeof(mem_string_t
*));
1118 if (out
->kvlist
== NULL
)
1120 asl_memory_record_free(s
, out
);
1121 *type
= ASL_QUERY_MATCH_ERROR
;
1125 out
->kvlist
[out
->kvcount
++] = mkey
;
1126 out
->kvlist
[out
->kvcount
++] = mval
;
1134 asl_memory_fast_match(asl_memory_t
*s
, mem_record_t
*r
, uint32_t qtype
, mem_record_t
*q
)
1138 if (s
== NULL
) return 0;
1139 if (r
== NULL
) return 0;
1140 if (q
== NULL
) return 1;
1142 if ((qtype
& ASL_QUERY_MATCH_MSG_ID
) && (q
->mid
!= r
->mid
)) return 0;
1143 if ((qtype
& ASL_QUERY_MATCH_TIME
) && (q
->time
!= r
->time
)) return 0;
1144 if ((qtype
& ASL_QUERY_MATCH_NANO
) && (q
->nano
!= r
->nano
)) return 0;
1145 if ((qtype
& ASL_QUERY_MATCH_LEVEL
) && (q
->level
!= r
->level
)) return 0;
1146 if ((qtype
& ASL_QUERY_MATCH_PID
) && (q
->pid
!= r
->pid
)) return 0;
1147 if ((qtype
& ASL_QUERY_MATCH_UID
) && (q
->uid
!= r
->uid
)) return 0;
1148 if ((qtype
& ASL_QUERY_MATCH_GID
) && (q
->gid
!= r
->gid
)) return 0;
1149 if ((qtype
& ASL_QUERY_MATCH_RUID
) && (q
->ruid
!= r
->ruid
)) return 0;
1150 if ((qtype
& ASL_QUERY_MATCH_RGID
) && (q
->rgid
!= r
->rgid
)) return 0;
1151 if ((qtype
& ASL_QUERY_MATCH_REF_PID
) && (q
->refpid
!= r
->refpid
)) return 0;
1152 if ((qtype
& ASL_QUERY_MATCH_HOST
) && (q
->host
!= r
->host
)) return 0;
1153 if ((qtype
& ASL_QUERY_MATCH_SENDER
) && (q
->sender
!= r
->sender
)) return 0;
1154 if ((qtype
& ASL_QUERY_MATCH_SMUUID
) && (q
->sender_mach_uuid
!= r
->sender_mach_uuid
)) return 0;
1155 if ((qtype
& ASL_QUERY_MATCH_FACILITY
) && (q
->facility
!= r
->facility
)) return 0;
1156 if ((qtype
& ASL_QUERY_MATCH_MESSAGE
) && (q
->message
!= r
->message
)) return 0;
1157 if ((qtype
& ASL_QUERY_MATCH_REF_PROC
) && (q
->refproc
!= r
->refproc
)) return 0;
1158 if ((qtype
& ASL_QUERY_MATCH_SESSION
) && (q
->session
!= r
->session
)) return 0;
1160 for (i
= 0; i
< q
->kvcount
; i
+= 2)
1162 for (j
= 0; j
< r
->kvcount
; j
+= 2)
1164 if (q
->kvlist
[i
] == r
->kvlist
[j
])
1166 if (q
->kvlist
[i
+ 1] == r
->kvlist
[j
+ 1]) break;
1171 if (j
>= r
->kvcount
) return 0;
1178 asl_memory_slow_match(asl_memory_t
*s
, mem_record_t
*r
, asl_msg_t
*rawq
)
1184 status
= asl_memory_message_decode(s
, r
, &rawm
);
1185 if (status
!= ASL_STATUS_OK
) return 0;
1188 if (asl_msg_cmp((asl_msg_t
*)rawq
, (asl_msg_t
*)rawm
) != 0) status
= 1;
1189 asl_msg_release(rawm
);
1194 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
)
1196 uint32_t status
, i
, where
, start
, j
, do_match
, did_match
, rescount
, *qtype
;
1200 struct timeval now
, finish
;
1202 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1203 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1208 qcount
= asl_msg_list_count(query
);
1216 qp
= (mem_record_t
**)calloc(qcount
, sizeof(mem_record_t
*));
1217 if (qp
== NULL
) return ASL_STATUS_NO_MEMORY
;
1219 qtype
= (uint32_t *)calloc(qcount
, sizeof(uint32_t));
1223 return ASL_STATUS_NO_MEMORY
;
1227 for (i
= 0; i
< qcount
; i
++)
1229 qp
[i
] = asl_memory_query_to_record(s
, asl_msg_list_get_index(query
, i
), &(qtype
[i
]));
1230 if (qtype
[i
] == ASL_QUERY_MATCH_ERROR
)
1232 for (j
= 0; j
< i
; j
++) asl_memory_record_free(s
, qp
[j
]);
1235 return ASL_STATUS_FAILED
;
1238 if (qtype
[i
] != ASL_QUERY_MATCH_TRUE
) do_match
= 1;
1242 for (i
= 0; i
< s
->record_count
; i
++)
1246 where
= (s
->record_first
+ i
) % s
->record_count
;
1247 if (s
->record
[where
]->mid
== 0) continue;
1248 if (s
->record
[where
]->mid
>= start_id
) break;
1252 where
= ((s
->record_count
- (i
+ 1)) + s
->record_first
) % s
->record_count
;
1253 if (s
->record
[where
]->mid
== 0) continue;
1254 if (s
->record
[where
]->mid
<= start_id
) break;
1258 if (i
>= s
->record_count
)
1262 for (i
= 0; i
< qcount
; i
++) asl_memory_record_free(s
, qp
[i
]);
1267 return ASL_STATUS_OK
;
1270 /* start the timer if a duration was specified */
1271 memset(&finish
, 0, sizeof(struct timeval
));
1274 if (gettimeofday(&finish
, NULL
) == 0)
1276 finish
.tv_sec
+= (duration
/ USEC_PER_SEC
);
1277 finish
.tv_usec
+= (duration
% USEC_PER_SEC
);
1278 if (finish
.tv_usec
> USEC_PER_SEC
)
1280 finish
.tv_usec
-= USEC_PER_SEC
;
1286 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
1287 memset(&finish
, 0, sizeof(struct timeval
));
1294 * loop through records
1296 for (i
= 0; i
< s
->record_count
; i
++)
1298 status
= ASL_STATUS_INVALID_ID
;
1299 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
);
1301 if ((status
== ASL_STATUS_OK
) && (uuid_str
!= NULL
))
1303 if (s
->record
[where
]->sender_mach_uuid
== NULL
) status
= ASL_STATUS_INVALID_ID
;
1304 else if (strcmp(s
->record
[where
]->sender_mach_uuid
->str
, uuid_str
) != 0) status
= ASL_STATUS_INVALID_ID
;
1307 if (status
!= ASL_STATUS_OK
)
1312 if (where
>= s
->record_count
) where
= 0;
1316 if (where
== 0) where
= s
->record_count
- 1;
1320 if (where
== s
->record_first
) break;
1324 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1325 *last_id
= s
->record
[where
]->mid
;
1332 for (j
= 0; (j
< qcount
) && (did_match
== 0); j
++)
1334 if (qtype
[j
] == ASL_QUERY_MATCH_TRUE
)
1338 else if (qtype
[j
] == ASL_QUERY_MATCH_FALSE
)
1342 else if (qtype
[j
] == ASL_QUERY_MATCH_SLOW
)
1344 did_match
= asl_memory_slow_match(s
, s
->record
[where
], asl_msg_list_get_index(query
, j
));
1348 did_match
= asl_memory_fast_match(s
, s
->record
[where
], qtype
[j
], qp
[j
]);
1355 s
->record
[where
]->flags
|= ASL_MSG_FLAG_SEARCH_MATCH
;
1357 if ((count
!= 0) && (rescount
>= count
)) break;
1360 /* check the timer */
1361 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
1363 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
1369 if (where
>= s
->record_count
) where
= 0;
1373 if (where
== 0) where
= s
->record_count
- 1;
1377 if (where
== s
->record_first
) break;
1382 for (i
= 0; i
< qcount
; i
++) asl_memory_record_free(s
, qp
[i
]);
1388 if (rescount
== 0) return ASL_STATUS_OK
;
1390 *res
= asl_msg_list_new();
1391 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1398 if (s
->record
[where
]->flags
& ASL_MSG_FLAG_SEARCH_MATCH
)
1400 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1402 status
= asl_memory_message_decode(s
, s
->record
[where
], &m
);
1403 if (status
!= ASL_STATUS_OK
)
1405 asl_msg_list_release(*res
);
1410 asl_msg_list_append(*res
, m
);
1413 if (n
== rescount
) break;
1419 if (where
>= s
->record_count
) where
= 0;
1423 if (where
== 0) where
= s
->record_count
- 1;
1427 if (where
== s
->record_first
) break;
1430 return ASL_STATUS_OK
;
1434 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
)
1436 return asl_memory_match_restricted_uuid(s
, query
, res
, last_id
, start_id
, count
, 0, direction
, ruid
, rgid
, NULL
);