2 * Copyright (c) 2007-2008 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@
25 #include <asl_mini_memory.h>
29 #include <sys/errno.h>
31 #include <sys/types.h>
33 #include <asl_private.h>
35 #define DEFAULT_MAX_RECORDS 256
36 #define MEM_STRING_HEADER_SIZE 8
37 #define CFLOG_LOCAL_TIME_KEY "CFLog Local Time"
38 #define CFLOG_THREAD_KEY "CFLog Thread"
40 #define forever for(;;)
41 extern time_t asl_parse_time(const char *str
);
42 extern int asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
);
45 asl_mini_memory_statistics(asl_mini_memory_t
*s
, aslmsg
*msg
)
52 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
53 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
55 out
= (aslmsg
)calloc(1, sizeof(asl_msg_t
));
56 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
58 size
= sizeof(asl_mini_memory_t
);
59 size
+= ((s
->record_count
+ 1) * sizeof(mini_mem_record_t
));
61 for (i
= 0; i
< s
->string_count
; i
++)
63 size
+= MEM_STRING_HEADER_SIZE
;
64 if (((mini_mem_string_t
*)s
->string_cache
[i
])->str
!= NULL
) size
+= (strlen(((mini_mem_string_t
*)s
->string_cache
[i
])->str
) + 1);
67 snprintf(str
, sizeof(str
), "%llu", size
);
68 asl_set(out
, "Size", str
);
71 for (i
= 0; i
< s
->record_count
; i
++) if (s
->record
[i
]->mid
!= 0) n
++;
73 snprintf(str
, sizeof(str
), "%u", n
);
74 asl_set(out
, "RecordCount", str
);
76 snprintf(str
, sizeof(str
), "%u", s
->string_count
);
77 asl_set(out
, "StringCount", str
);
84 asl_mini_memory_close(asl_mini_memory_t
*s
)
88 if (s
== NULL
) return ASL_STATUS_OK
;
90 if (s
->record
!= NULL
)
92 for (i
= 0; i
< s
->record_count
; i
++)
94 if (s
->record
[i
] != NULL
) free(s
->record
[i
]);
102 if (s
->buffer_record
!= NULL
) free(s
->buffer_record
);
104 if (s
->string_cache
!= NULL
)
106 for (i
= 0; i
< s
->string_count
; i
++)
108 if (s
->string_cache
[i
] != NULL
) free(s
->string_cache
[i
]);
109 s
->string_cache
[i
] = NULL
;
112 free(s
->string_cache
);
113 s
->string_cache
= NULL
;
118 return ASL_STATUS_OK
;
122 asl_mini_memory_open(uint32_t max_records
, asl_mini_memory_t
**s
)
124 asl_mini_memory_t
*out
;
127 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
129 if (max_records
== 0) max_records
= DEFAULT_MAX_RECORDS
;
131 out
= calloc(1, sizeof(asl_mini_memory_t
));
132 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
134 out
->record_count
= max_records
;
135 out
->record
= (mini_mem_record_t
**)calloc(max_records
, sizeof(mini_mem_record_t
*));
136 if (out
->record
== NULL
)
139 return ASL_STATUS_NO_MEMORY
;
142 for (i
= 0; i
< max_records
; i
++)
144 out
->record
[i
] = (mini_mem_record_t
*)calloc(1, sizeof(mini_mem_record_t
));
145 if (out
->record
[i
] == NULL
)
147 asl_mini_memory_close(out
);
148 return ASL_STATUS_NO_MEMORY
;
152 out
->buffer_record
= (mini_mem_record_t
*)calloc(1, sizeof(mini_mem_record_t
));
153 if (out
->buffer_record
== NULL
)
155 asl_mini_memory_close(out
);
156 return ASL_STATUS_NO_MEMORY
;
162 return ASL_STATUS_OK
;
165 static mini_mem_string_t
*
166 mem_string_new(const char *str
, uint32_t len
, uint32_t hash
)
168 mini_mem_string_t
*out
;
171 if (str
== NULL
) return NULL
;
173 ss
= MEM_STRING_HEADER_SIZE
+ len
+ 1;
174 out
= (mini_mem_string_t
*)calloc(1, ss
);
175 if (out
== NULL
) return NULL
;
179 memcpy(out
->str
, str
, len
);
185 * Find the first hash greater than or equal to a given hash in the string cache.
186 * Return s->string_count if hash is greater that or equal to last hash in the string cache.
187 * Caller must check if the hashes match or not.
189 * This routine is used both to find strings in the cache and to determine where to insert
190 * new strings. Note that the caller needs to do extra work after calling this routine.
193 asl_mini_memory_string_cache_search_hash(asl_mini_memory_t
*s
, uint32_t hash
)
195 uint32_t top
, bot
, mid
, range
;
196 mini_mem_string_t
*ms
;
198 if (s
->string_count
== 0) return 0;
199 if (s
->string_count
== 1)
201 ms
= (mini_mem_string_t
*)s
->string_cache
[0];
202 if (hash
< ms
->hash
) return 0;
206 top
= s
->string_count
- 1;
213 ms
= (mini_mem_string_t
*)s
->string_cache
[mid
];
215 if (hash
== ms
->hash
)
219 ms
= (mini_mem_string_t
*)s
->string_cache
[mid
- 1];
220 if (hash
!= ms
->hash
) break;
228 ms
= (mini_mem_string_t
*)s
->string_cache
[mid
];
229 if (hash
< ms
->hash
) top
= mid
;
234 mid
= bot
+ (range
/ 2);
237 ms
= (mini_mem_string_t
*)s
->string_cache
[bot
];
238 if (hash
<= ms
->hash
) return bot
;
240 ms
= (mini_mem_string_t
*)s
->string_cache
[top
];
241 if (hash
<= ms
->hash
) return top
;
243 return s
->string_count
;
247 * Search the string cache.
248 * If the string is in the cache, increment refcount and return it.
249 * If the string is not in cache and create flag is on, create a new string.
250 * Otherwise, return NULL.
252 static mini_mem_string_t
*
253 asl_mini_memory_string_retain(asl_mini_memory_t
*s
, const char *str
, int create
)
255 uint32_t i
, where
, hash
, len
;
257 if (s
== NULL
) return NULL
;
258 if (str
== NULL
) return NULL
;
261 /* check the cache */
262 hash
= asl_core_string_hash(str
, len
);
263 where
= asl_mini_memory_string_cache_search_hash(s
, hash
);
265 /* asl_mini_memory_string_cache_search_hash just tells us where to look */
266 if (where
< s
->string_count
)
268 while (((mini_mem_string_t
*)(s
->string_cache
[where
]))->hash
== hash
)
270 if (!strcmp(str
, ((mini_mem_string_t
*)(s
->string_cache
[where
]))->str
))
272 ((mini_mem_string_t
*)(s
->string_cache
[where
]))->refcount
++;
273 return s
->string_cache
[where
];
281 if (create
== 0) return NULL
;
283 /* create a new mini_mem_string_t and insert into the cache at index 'where' */
284 if (s
->string_count
== 0)
286 s
->string_cache
= (void **)calloc(1, sizeof(void *));
290 s
->string_cache
= (void **)reallocf(s
->string_cache
, (s
->string_count
+ 1) * sizeof(void *));
291 for (i
= s
->string_count
; i
> where
; i
--) s
->string_cache
[i
] = s
->string_cache
[i
- 1];
294 if (s
->string_cache
== NULL
)
301 s
->string_cache
[where
] = mem_string_new(str
, len
, hash
);
303 return s
->string_cache
[where
];
307 asl_mini_memory_string_release(asl_mini_memory_t
*s
, mini_mem_string_t
*m
)
311 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
312 if (m
== NULL
) return ASL_STATUS_OK
;
314 if (m
->refcount
> 0) m
->refcount
--;
315 if (m
->refcount
> 0) return ASL_STATUS_OK
;
317 where
= asl_mini_memory_string_cache_search_hash(s
, m
->hash
);
318 if (((mini_mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
320 while (s
->string_cache
[where
] != m
)
322 if (((mini_mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
325 if (where
>= s
->string_count
) return ASL_STATUS_OK
;
328 for (i
= where
+ 1; i
< s
->string_count
; i
++) s
->string_cache
[i
- 1] = s
->string_cache
[i
];
333 if (s
->string_count
== 0)
335 free(s
->string_cache
);
336 s
->string_cache
= NULL
;
337 return ASL_STATUS_OK
;
340 s
->string_cache
= (void **)reallocf(s
->string_cache
, s
->string_count
* sizeof(void *));
341 if (s
->string_cache
== NULL
)
344 return ASL_STATUS_NO_MEMORY
;
347 return ASL_STATUS_OK
;
351 * Release all a record's strings and reset it's values
354 asl_mini_memory_record_clear(asl_mini_memory_t
*s
, mini_mem_record_t
*r
)
358 if (s
== NULL
) return;
359 if (r
== NULL
) return;
361 asl_mini_memory_string_release(s
, r
->sender
);
362 asl_mini_memory_string_release(s
, r
->facility
);
363 asl_mini_memory_string_release(s
, r
->message
);
365 for (i
= 0; i
< r
->kvcount
; i
++) asl_mini_memory_string_release(s
, r
->kvlist
[i
]);
367 if (r
->kvlist
!= NULL
) free(r
->kvlist
);
368 memset(r
, 0, sizeof(mini_mem_record_t
));
372 asl_mini_memory_record_free(asl_mini_memory_t
*s
, mini_mem_record_t
*r
)
374 asl_mini_memory_record_clear(s
, r
);
379 * Encode an aslmsg as a record structure.
380 * Creates and caches strings.
383 asl_mini_memory_message_encode(asl_mini_memory_t
*s
, asl_msg_t
*msg
, mini_mem_record_t
*r
)
386 mini_mem_string_t
*k
, *v
;
388 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
389 if (msg
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
390 if (r
== NULL
) return ASL_STATUS_INVALID_ARG
;
392 memset(r
, 0, sizeof(mini_mem_record_t
));
395 r
->level
= ASL_LEVEL_DEBUG
;
397 r
->time
= (uint64_t)-1;
399 for (i
= 0; i
< msg
->count
; i
++)
401 if (msg
->key
[i
] == NULL
) continue;
403 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
405 if (msg
->val
[i
] != NULL
) r
->time
= asl_parse_time(msg
->val
[i
]);
407 else if (!strcmp(msg
->key
[i
], ASL_KEY_SENDER
))
409 if (msg
->val
[i
] != NULL
) r
->sender
= asl_mini_memory_string_retain(s
, msg
->val
[i
], 1);
411 else if (!strcmp(msg
->key
[i
], ASL_KEY_PID
))
413 if (msg
->val
[i
] != NULL
) r
->pid
= atoi(msg
->val
[i
]);
415 else if (!strcmp(msg
->key
[i
], ASL_KEY_LEVEL
))
417 if (msg
->val
[i
] != NULL
) r
->level
= atoi(msg
->val
[i
]);
419 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG
))
421 if (msg
->val
[i
] != NULL
) r
->message
= asl_mini_memory_string_retain(s
, msg
->val
[i
], 1);
423 else if (!strcmp(msg
->key
[i
], ASL_KEY_FACILITY
))
425 if (msg
->val
[i
] != NULL
) r
->facility
= asl_mini_memory_string_retain(s
, msg
->val
[i
], 1);
427 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG_ID
))
432 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME_NSEC
))
437 else if (!strcmp(msg
->key
[i
], ASL_KEY_HOST
))
442 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PID
))
447 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PROC
))
452 else if (!strcmp(msg
->key
[i
], ASL_KEY_SESSION
))
457 else if (!strcmp(msg
->key
[i
], ASL_KEY_UID
))
462 else if (!strcmp(msg
->key
[i
], ASL_KEY_GID
))
467 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_UID
))
472 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_GID
))
477 else if (!strcmp(msg
->key
[i
], CFLOG_LOCAL_TIME_KEY
))
482 else if (!strcmp(msg
->key
[i
], CFLOG_THREAD_KEY
))
489 k
= asl_mini_memory_string_retain(s
, msg
->key
[i
], 1);
490 if (k
== NULL
) continue;
493 if (msg
->val
[i
] != NULL
) v
= asl_mini_memory_string_retain(s
, msg
->val
[i
], 1);
497 r
->kvlist
= (mini_mem_string_t
**)calloc(2, sizeof(mini_mem_string_t
*));
501 r
->kvlist
= (mini_mem_string_t
**)realloc(r
->kvlist
, (r
->kvcount
+ 2) * sizeof(mini_mem_string_t
*));
504 if (r
->kvlist
== NULL
)
506 asl_mini_memory_record_clear(s
, r
);
507 return ASL_STATUS_NO_MEMORY
;
510 r
->kvlist
[r
->kvcount
++] = k
;
511 r
->kvlist
[r
->kvcount
++] = v
;
515 return ASL_STATUS_OK
;
519 asl_mini_memory_save(asl_mini_memory_t
*s
, aslmsg msg
, uint64_t *mid
)
522 mini_mem_record_t
*t
;
524 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
525 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
527 /* asl_mini_memory_message_encode creates and caches strings */
528 status
= asl_mini_memory_message_encode(s
, msg
, s
->buffer_record
);
529 if (status
!= ASL_STATUS_OK
) return status
;
531 s
->buffer_record
->mid
= s
->next_id
;
534 /* clear the first record */
535 t
= s
->record
[s
->record_first
];
536 asl_mini_memory_record_clear(s
, t
);
538 /* add the new record to the record list (swap in the buffer record) */
539 s
->record
[s
->record_first
] = s
->buffer_record
;
540 s
->buffer_record
= t
;
542 /* record list is a circular queue */
544 if (s
->record_first
>= s
->record_count
) s
->record_first
= 0;
546 *mid
= s
->buffer_record
->mid
;
552 * Decodes a record structure.
555 asl_mini_memory_message_decode(asl_mini_memory_t
*s
, mini_mem_record_t
*r
, asl_msg_t
**out
)
560 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
561 if (r
== NULL
) return ASL_STATUS_INVALID_ARG
;
562 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
566 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
567 if (msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
569 msg
->type
= ASL_TYPE_MSG
;
570 /* Level and Message ID are always set */
573 if (r
->time
!= (uint64_t)-1) msg
->count
++;
574 if (r
->sender
!= NULL
) msg
->count
++;
575 if (r
->facility
!= NULL
) msg
->count
++;
576 if (r
->pid
!= -1) msg
->count
++;
577 if (r
->message
!= NULL
) msg
->count
++;
579 msg
->count
+= (r
->kvcount
/ 2);
581 msg
->key
= (char **)calloc(msg
->count
, sizeof(char *));
582 if (msg
->key
== NULL
)
585 return ASL_STATUS_NO_MEMORY
;
588 msg
->val
= (char **)calloc(msg
->count
, sizeof(char *));
589 if (msg
->val
== NULL
)
593 return ASL_STATUS_NO_MEMORY
;
599 msg
->key
[n
] = strdup(ASL_KEY_MSG_ID
);
600 if (msg
->key
[n
] == NULL
)
603 return ASL_STATUS_NO_MEMORY
;
606 asprintf(&(msg
->val
[n
]), "%lu", r
->mid
);
607 if (msg
->val
[n
] == NULL
)
610 return ASL_STATUS_NO_MEMORY
;
615 msg
->key
[n
] = strdup(ASL_KEY_LEVEL
);
616 if (msg
->key
[n
] == NULL
)
619 return ASL_STATUS_NO_MEMORY
;
622 asprintf(&(msg
->val
[n
]), "%u", r
->level
);
623 if (msg
->val
[n
] == NULL
)
626 return ASL_STATUS_NO_MEMORY
;
631 if (r
->time
!= (uint64_t)-1)
633 msg
->key
[n
] = strdup(ASL_KEY_TIME
);
634 if (msg
->key
[n
] == NULL
)
637 return ASL_STATUS_NO_MEMORY
;
640 asprintf(&(msg
->val
[n
]), "%llu", r
->time
);
641 if (msg
->val
[n
] == NULL
)
644 return ASL_STATUS_NO_MEMORY
;
650 if (r
->sender
!= NULL
)
652 msg
->key
[n
] = strdup(ASL_KEY_SENDER
);
653 if (msg
->key
[n
] == NULL
)
656 return ASL_STATUS_NO_MEMORY
;
659 msg
->val
[n
] = strdup(r
->sender
->str
);
664 if (r
->facility
!= NULL
)
666 msg
->key
[n
] = strdup(ASL_KEY_FACILITY
);
667 if (msg
->key
[n
] == NULL
)
670 return ASL_STATUS_NO_MEMORY
;
673 msg
->val
[n
] = strdup(r
->facility
->str
);
680 msg
->key
[n
] = strdup(ASL_KEY_PID
);
681 if (msg
->key
[n
] == NULL
)
684 return ASL_STATUS_NO_MEMORY
;
687 asprintf(&(msg
->val
[n
]), "%d", r
->pid
);
688 if (msg
->val
[n
] == NULL
)
691 return ASL_STATUS_NO_MEMORY
;
697 if (r
->message
!= NULL
)
699 msg
->key
[n
] = strdup(ASL_KEY_MSG
);
700 if (msg
->key
[n
] == NULL
)
703 return ASL_STATUS_NO_MEMORY
;
706 msg
->val
[n
] = strdup(r
->message
->str
);
710 /* Key - Value List */
711 for (i
= 0; i
< r
->kvcount
; i
++)
713 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) msg
->key
[n
] = strdup(r
->kvlist
[i
]->str
);
715 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) msg
->val
[n
] = strdup(r
->kvlist
[i
]->str
);
720 return ASL_STATUS_OK
;
724 asl_mini_memory_fetch(asl_mini_memory_t
*s
, uint64_t mid
, aslmsg
*msg
)
728 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
729 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
731 for (i
= 0; i
< s
->record_count
; i
++)
733 if (s
->record
[i
]->mid
== 0) break;
734 if (s
->record
[i
]->mid
== mid
) return asl_mini_memory_message_decode(s
, s
->record
[i
], msg
);
737 return ASL_STATUS_INVALID_ID
;
740 static mini_mem_record_t
*
741 asl_mini_memory_query_to_record(asl_mini_memory_t
*s
, asl_msg_t
*q
, uint32_t *type
)
743 mini_mem_record_t
*out
;
745 mini_mem_string_t
*key
, *val
;
747 if (type
== NULL
) return NULL
;
751 *type
= ASL_QUERY_MATCH_ERROR
;
755 /* NULL query matches anything */
756 *type
= ASL_QUERY_MATCH_TRUE
;
757 if (q
== NULL
) return NULL
;
758 if (q
->count
== 0) return NULL
;
761 /* we can only do fast match on equality tests */
762 *type
= ASL_QUERY_MATCH_SLOW
;
765 for (i
= 0; i
< q
->count
; i
++) if (q
->op
[i
] != ASL_QUERY_OP_EQUAL
) return NULL
;
768 out
= (mini_mem_record_t
*)calloc(1, sizeof(mini_mem_record_t
));
771 *type
= ASL_QUERY_MATCH_ERROR
;
775 for (i
= 0; i
< q
->count
; i
++)
777 if (q
->key
[i
] == NULL
) continue;
779 else if (!strcmp(q
->key
[i
], ASL_KEY_MSG_ID
))
781 if (q
->val
[i
] == NULL
) continue;
783 if (*type
& ASL_QUERY_MATCH_MSG_ID
)
785 asl_mini_memory_record_free(s
, out
);
786 *type
= ASL_QUERY_MATCH_SLOW
;
790 *type
|= ASL_QUERY_MATCH_MSG_ID
;
791 out
->mid
= atoll(q
->val
[i
]);
793 else if (!strcmp(q
->key
[i
], ASL_KEY_TIME
))
795 if (q
->val
[i
] == NULL
) continue;
797 if (*type
& ASL_QUERY_MATCH_TIME
)
799 asl_mini_memory_record_free(s
, out
);
800 *type
= ASL_QUERY_MATCH_SLOW
;
804 *type
|= ASL_QUERY_MATCH_TIME
;
805 out
->time
= asl_parse_time(q
->val
[i
]);
807 else if (!strcmp(q
->key
[i
], ASL_KEY_LEVEL
))
809 if (q
->val
[i
] == NULL
) continue;
811 if (*type
& ASL_QUERY_MATCH_LEVEL
)
813 asl_mini_memory_record_free(s
, out
);
814 *type
= ASL_QUERY_MATCH_SLOW
;
818 *type
|= ASL_QUERY_MATCH_LEVEL
;
819 out
->level
= atoi(q
->val
[i
]);
821 else if (!strcmp(q
->key
[i
], ASL_KEY_PID
))
823 if (q
->val
[i
] == NULL
) continue;
825 if (*type
& ASL_QUERY_MATCH_PID
)
827 asl_mini_memory_record_free(s
, out
);
828 *type
= ASL_QUERY_MATCH_SLOW
;
832 *type
|= ASL_QUERY_MATCH_PID
;
833 out
->pid
= atoi(q
->val
[i
]);
835 else if (!strcmp(q
->key
[i
], ASL_KEY_SENDER
))
837 if (q
->val
[i
] == NULL
) continue;
839 if (*type
& ASL_QUERY_MATCH_SENDER
)
841 asl_mini_memory_record_free(s
, out
);
842 *type
= ASL_QUERY_MATCH_SLOW
;
846 *type
|= ASL_QUERY_MATCH_SENDER
;
847 out
->sender
= asl_mini_memory_string_retain(s
, q
->val
[i
], 0);
848 if (out
->sender
== NULL
)
850 asl_mini_memory_record_free(s
, out
);
851 *type
= ASL_QUERY_MATCH_FALSE
;
855 else if (!strcmp(q
->key
[i
], ASL_KEY_FACILITY
))
857 if (q
->val
[i
] == NULL
) continue;
859 if (*type
& ASL_QUERY_MATCH_FACILITY
)
861 asl_mini_memory_record_free(s
, out
);
862 *type
= ASL_QUERY_MATCH_SLOW
;
866 *type
|= ASL_QUERY_MATCH_FACILITY
;
867 out
->facility
= asl_mini_memory_string_retain(s
, q
->val
[i
], 0);
868 if (out
->facility
== NULL
)
870 asl_mini_memory_record_free(s
, out
);
871 *type
= ASL_QUERY_MATCH_FALSE
;
875 else if (!strcmp(q
->key
[i
], ASL_KEY_MSG
))
877 if (q
->val
[i
] == NULL
) continue;
879 if (*type
& ASL_QUERY_MATCH_MESSAGE
)
881 asl_mini_memory_record_free(s
, out
);
882 *type
= ASL_QUERY_MATCH_SLOW
;
886 *type
|= ASL_QUERY_MATCH_MESSAGE
;
887 out
->message
= asl_mini_memory_string_retain(s
, q
->val
[i
], 0);
888 if (out
->message
== NULL
)
890 asl_mini_memory_record_free(s
, out
);
891 *type
= ASL_QUERY_MATCH_FALSE
;
897 key
= asl_mini_memory_string_retain(s
, q
->key
[i
], 0);
900 asl_mini_memory_record_free(s
, out
);
901 *type
= ASL_QUERY_MATCH_FALSE
;
905 for (j
= 0; j
< out
->kvcount
; j
+= 2)
907 if (out
->kvlist
[j
] == key
)
909 asl_mini_memory_record_free(s
, out
);
910 *type
= ASL_QUERY_MATCH_SLOW
;
915 val
= asl_mini_memory_string_retain(s
, q
->val
[i
], 0);
917 if (out
->kvcount
== 0)
919 out
->kvlist
= (mini_mem_string_t
**)calloc(2, sizeof(mini_mem_string_t
*));
923 out
->kvlist
= (mini_mem_string_t
**)realloc(out
->kvlist
, (out
->kvcount
+ 2) * sizeof(mini_mem_string_t
*));
926 if (out
->kvlist
== NULL
)
928 asl_mini_memory_record_free(s
, out
);
929 *type
= ASL_QUERY_MATCH_ERROR
;
933 out
->kvlist
[out
->kvcount
++] = key
;
934 out
->kvlist
[out
->kvcount
++] = val
;
942 asl_mini_memory_fast_match(asl_mini_memory_t
*s
, mini_mem_record_t
*r
, uint32_t qtype
, mini_mem_record_t
*q
)
946 if (s
== NULL
) return 0;
947 if (r
== NULL
) return 0;
948 if (q
== NULL
) return 1;
950 if ((qtype
& ASL_QUERY_MATCH_MSG_ID
) && (q
->mid
!= r
->mid
)) return 0;
951 if ((qtype
& ASL_QUERY_MATCH_TIME
) && (q
->time
!= r
->time
)) return 0;
952 if ((qtype
& ASL_QUERY_MATCH_LEVEL
) && (q
->level
!= r
->level
)) return 0;
953 if ((qtype
& ASL_QUERY_MATCH_PID
) && (q
->pid
!= r
->pid
)) return 0;
954 if ((qtype
& ASL_QUERY_MATCH_SENDER
) && (q
->sender
!= r
->sender
)) return 0;
955 if ((qtype
& ASL_QUERY_MATCH_FACILITY
) && (q
->facility
!= r
->facility
)) return 0;
956 if ((qtype
& ASL_QUERY_MATCH_MESSAGE
) && (q
->message
!= r
->message
)) return 0;
958 for (i
= 0; i
< q
->kvcount
; i
+= 2)
960 for (j
= 0; j
< r
->kvcount
; j
+= 2)
962 if (q
->kvlist
[i
] == r
->kvlist
[j
])
964 if (q
->kvlist
[i
+ 1] == r
->kvlist
[j
+ 1]) break;
969 if (j
>= r
->kvcount
) return 0;
976 asl_mini_memory_slow_match(asl_mini_memory_t
*s
, mini_mem_record_t
*r
, mini_mem_record_t
*q
, asl_msg_t
*rawq
)
982 status
= asl_mini_memory_message_decode(s
, r
, &rawm
);
983 if (status
!= ASL_STATUS_OK
) return 0;
986 if (asl_msg_cmp(rawq
, rawm
) != 0) status
= 1;
992 asl_mini_memory_match(asl_mini_memory_t
*s
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
994 uint32_t status
, i
, where
, start
, j
, do_match
, did_match
, rescount
, *qtype
;
995 mini_mem_record_t
**qp
;
998 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
999 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1006 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0)))
1012 qp
= (mini_mem_record_t
**)calloc(query
->count
, sizeof(mini_mem_record_t
*));
1013 if (qp
== NULL
) return ASL_STATUS_NO_MEMORY
;
1015 qtype
= (uint32_t *)calloc(query
->count
, sizeof(uint32_t));
1019 return ASL_STATUS_NO_MEMORY
;
1023 for (i
= 0; i
< query
->count
; i
++)
1025 qp
[i
] = asl_mini_memory_query_to_record(s
, query
->msg
[i
], &(qtype
[i
]));
1026 if (qtype
[i
] == ASL_QUERY_MATCH_ERROR
)
1028 for (j
= 0; j
< i
; j
++) asl_mini_memory_record_free(s
, qp
[j
]);
1031 return ASL_STATUS_FAILED
;
1034 if (qtype
[i
] != ASL_QUERY_MATCH_TRUE
) do_match
= 1;
1038 for (i
= 0; i
< s
->record_count
; i
++)
1042 where
= (s
->record_first
+ i
) % s
->record_count
;
1043 if (s
->record
[where
]->mid
== 0) continue;
1044 if (s
->record
[where
]->mid
>= start_id
) break;
1048 where
= ((s
->record_count
- (i
+ 1)) + s
->record_first
) % s
->record_count
;
1049 if (s
->record
[where
]->mid
== 0) continue;
1050 if (s
->record
[where
]->mid
<= start_id
) break;
1054 if (i
>= s
->record_count
)
1058 for (i
= 0; i
< query
->count
; i
++) asl_mini_memory_record_free(s
, qp
[i
]);
1063 return ASL_STATUS_OK
;
1069 * loop through records
1071 for (i
= 0; i
< s
->record_count
; i
++)
1073 if (s
->record
[where
]->mid
== 0)
1078 if (where
>= s
->record_count
) where
= 0;
1082 if (where
== 0) where
= s
->record_count
- 1;
1086 if (where
== s
->record_first
) break;
1090 s
->record
[where
]->flags
&= ASL_MINI_MSG_FLAG_SEARCH_CLEAR
;
1091 *last_id
= s
->record
[where
]->mid
;
1098 for (j
= 0; (j
< query
->count
) && (did_match
== 0); j
++)
1100 if (qtype
[j
] == ASL_QUERY_MATCH_TRUE
)
1104 else if (qtype
[j
] == ASL_QUERY_MATCH_SLOW
)
1106 did_match
= asl_mini_memory_slow_match(s
, s
->record
[where
], qp
[j
], query
->msg
[j
]);
1110 did_match
= asl_mini_memory_fast_match(s
, s
->record
[where
], qtype
[j
], qp
[j
]);
1117 s
->record
[where
]->flags
|= ASL_MINI_MSG_FLAG_SEARCH_MATCH
;
1119 if ((count
!= 0) && (rescount
>= count
)) break;
1125 if (where
>= s
->record_count
) where
= 0;
1129 if (where
== 0) where
= s
->record_count
- 1;
1133 if (where
== s
->record_first
) break;
1138 for (i
= 0; i
< query
->count
; i
++) asl_mini_memory_record_free(s
, qp
[i
]);
1144 if (rescount
== 0) return ASL_STATUS_OK
;
1146 *res
= (asl_msg_list_t
*)calloc(1, sizeof(asl_msg_list_t
));
1147 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1149 (*res
)->count
= rescount
;
1151 (*res
)->msg
= (asl_msg_t
**)calloc(rescount
, sizeof(asl_msg_t
*));
1152 if ((*res
)->msg
== NULL
)
1156 return ASL_STATUS_NO_MEMORY
;
1162 if (s
->record
[where
]->flags
& ASL_MINI_MSG_FLAG_SEARCH_MATCH
)
1164 s
->record
[where
]->flags
&= ASL_MINI_MSG_FLAG_SEARCH_CLEAR
;
1166 status
= asl_mini_memory_message_decode(s
, s
->record
[where
], &m
);
1167 if (status
!= ASL_STATUS_OK
)
1169 aslresponse_free(*res
);
1174 (*res
)->msg
[(*res
)->curr
++] = m
;
1175 if ((*res
)->curr
== rescount
) break;
1181 if (where
>= s
->record_count
) where
= 0;
1185 if (where
== 0) where
= s
->record_count
- 1;
1189 if (where
== s
->record_first
) break;
1193 return ASL_STATUS_OK
;