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_memory.h>
29 #include <sys/errno.h>
31 #include <sys/types.h>
33 #include <asl_private.h>
35 #define DEFAULT_MAX_RECORDS 2000
36 #define MEM_STRING_HEADER_SIZE 8
38 #define forever for(;;)
39 extern time_t asl_parse_time(const char *str
);
40 extern int asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
);
43 asl_memory_statistics(asl_memory_t
*s
, aslmsg
*msg
)
50 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
51 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
53 out
= (aslmsg
)calloc(1, sizeof(asl_msg_t
));
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
+= MEM_STRING_HEADER_SIZE
;
62 if (((mem_string_t
*)s
->string_cache
[i
])->str
!= NULL
) size
+= (strlen(((mem_string_t
*)s
->string_cache
[i
])->str
) + 1);
65 snprintf(str
, sizeof(str
), "%llu", size
);
66 asl_set(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", n
);
72 asl_set(out
, "RecordCount", str
);
74 snprintf(str
, sizeof(str
), "%u", s
->string_count
);
75 asl_set(out
, "StringCount", str
);
82 asl_memory_close(asl_memory_t
*s
)
86 if (s
== NULL
) return ASL_STATUS_OK
;
88 if (s
->record
!= NULL
)
90 for (i
= 0; i
< s
->record_count
; i
++)
92 if (s
->record
[i
] != NULL
) free(s
->record
[i
]);
100 if (s
->buffer_record
!= NULL
) free(s
->buffer_record
);
102 if (s
->string_cache
!= NULL
)
104 for (i
= 0; i
< s
->string_count
; i
++)
106 if (s
->string_cache
[i
] != NULL
) free(s
->string_cache
[i
]);
107 s
->string_cache
[i
] = NULL
;
110 free(s
->string_cache
);
111 s
->string_cache
= NULL
;
116 return ASL_STATUS_OK
;
120 asl_memory_open(uint32_t max_records
, asl_memory_t
**s
)
125 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
127 if (max_records
== 0) max_records
= DEFAULT_MAX_RECORDS
;
129 out
= calloc(1, sizeof(asl_memory_t
));
130 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
132 out
->record_count
= max_records
;
133 out
->record
= (mem_record_t
**)calloc(max_records
, sizeof(mem_record_t
*));
134 if (out
->record
== NULL
)
137 return ASL_STATUS_NO_MEMORY
;
140 for (i
= 0; i
< max_records
; i
++)
142 out
->record
[i
] = (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
143 if (out
->record
[i
] == NULL
)
145 asl_memory_close(out
);
146 return ASL_STATUS_NO_MEMORY
;
150 out
->buffer_record
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
151 if (out
->buffer_record
== NULL
)
153 asl_memory_close(out
);
154 return ASL_STATUS_NO_MEMORY
;
158 return ASL_STATUS_OK
;
161 static mem_string_t
*
162 mem_string_new(const char *str
, uint32_t len
, uint32_t hash
)
167 if (str
== NULL
) return NULL
;
169 ss
= MEM_STRING_HEADER_SIZE
+ len
+ 1;
170 out
= (mem_string_t
*)calloc(1, ss
);
171 if (out
== NULL
) return NULL
;
175 memcpy(out
->str
, str
, len
);
181 * Find the first hash greater than or equal to a given hash in the string cache.
182 * Return s->string_count if hash is greater that or equal to last hash in the string cache.
183 * Caller must check if the hashes match or not.
185 * This routine is used both to find strings in the cache and to determine where to insert
186 * new strings. Note that the caller needs to do extra work after calling this routine.
189 asl_memory_string_cache_search_hash(asl_memory_t
*s
, uint32_t hash
)
191 uint32_t top
, bot
, mid
, range
;
194 if (s
->string_count
== 0) return 0;
195 if (s
->string_count
== 1)
197 ms
= (mem_string_t
*)s
->string_cache
[0];
198 if (hash
< ms
->hash
) return 0;
202 top
= s
->string_count
- 1;
209 ms
= (mem_string_t
*)s
->string_cache
[mid
];
211 if (hash
== ms
->hash
)
215 ms
= (mem_string_t
*)s
->string_cache
[mid
- 1];
216 if (hash
!= ms
->hash
) break;
224 ms
= (mem_string_t
*)s
->string_cache
[mid
];
225 if (hash
< ms
->hash
) top
= mid
;
230 mid
= bot
+ (range
/ 2);
233 ms
= (mem_string_t
*)s
->string_cache
[bot
];
234 if (hash
<= ms
->hash
) return bot
;
236 ms
= (mem_string_t
*)s
->string_cache
[top
];
237 if (hash
<= ms
->hash
) return top
;
239 return s
->string_count
;
243 * Search the string cache.
244 * If the string is in the cache, increment refcount and return it.
245 * If the string is not in cache and create flag is on, create a new string.
246 * Otherwise, return NULL.
248 static mem_string_t
*
249 asl_memory_string_retain(asl_memory_t
*s
, const char *str
, int create
)
251 uint32_t i
, where
, hash
, len
;
253 if (s
== NULL
) return NULL
;
254 if (str
== NULL
) return NULL
;
257 /* check the cache */
258 hash
= asl_core_string_hash(str
, len
);
259 where
= asl_memory_string_cache_search_hash(s
, hash
);
261 /* asl_memory_string_cache_search_hash just tells us where to look */
262 if (where
< s
->string_count
)
264 while (((mem_string_t
*)(s
->string_cache
[where
]))->hash
== hash
)
266 if (!strcmp(str
, ((mem_string_t
*)(s
->string_cache
[where
]))->str
))
268 ((mem_string_t
*)(s
->string_cache
[where
]))->refcount
++;
269 return s
->string_cache
[where
];
277 if (create
== 0) return NULL
;
279 /* create a new mem_string_t and insert into the cache at index 'where' */
280 if (s
->string_count
== 0)
282 s
->string_cache
= (void **)calloc(1, sizeof(void *));
286 s
->string_cache
= (void **)reallocf(s
->string_cache
, (s
->string_count
+ 1) * sizeof(void *));
287 for (i
= s
->string_count
; i
> where
; i
--) s
->string_cache
[i
] = s
->string_cache
[i
- 1];
290 if (s
->string_cache
== NULL
)
297 s
->string_cache
[where
] = mem_string_new(str
, len
, hash
);
299 return s
->string_cache
[where
];
303 asl_memory_string_release(asl_memory_t
*s
, mem_string_t
*m
)
307 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
308 if (m
== NULL
) return ASL_STATUS_OK
;
310 if (m
->refcount
> 0) m
->refcount
--;
311 if (m
->refcount
> 0) return ASL_STATUS_OK
;
313 where
= asl_memory_string_cache_search_hash(s
, m
->hash
);
314 if (((mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
316 while (s
->string_cache
[where
] != m
)
318 if (((mem_string_t
*)(s
->string_cache
[where
]))->hash
!= m
->hash
) return ASL_STATUS_OK
;
321 if (where
>= s
->string_count
) return ASL_STATUS_OK
;
324 for (i
= where
+ 1; i
< s
->string_count
; i
++) s
->string_cache
[i
- 1] = s
->string_cache
[i
];
329 if (s
->string_count
== 0)
331 free(s
->string_cache
);
332 s
->string_cache
= NULL
;
333 return ASL_STATUS_OK
;
336 s
->string_cache
= (void **)reallocf(s
->string_cache
, s
->string_count
* sizeof(void *));
337 if (s
->string_cache
== NULL
)
340 return ASL_STATUS_NO_MEMORY
;
343 return ASL_STATUS_OK
;
347 * Release all a record's strings and reset it's values
350 asl_memory_record_clear(asl_memory_t
*s
, mem_record_t
*r
)
354 if (s
== NULL
) return;
355 if (r
== NULL
) return;
357 asl_memory_string_release(s
, r
->host
);
358 asl_memory_string_release(s
, r
->sender
);
359 asl_memory_string_release(s
, r
->facility
);
360 asl_memory_string_release(s
, r
->message
);
361 asl_memory_string_release(s
, r
->refproc
);
362 asl_memory_string_release(s
, r
->session
);
364 for (i
= 0; i
< r
->kvcount
; i
++) asl_memory_string_release(s
, r
->kvlist
[i
]);
366 if (r
->kvlist
!= NULL
) free(r
->kvlist
);
367 memset(r
, 0, sizeof(mem_record_t
));
371 asl_memory_record_free(asl_memory_t
*s
, mem_record_t
*r
)
373 asl_memory_record_clear(s
, r
);
378 * Encode an aslmsg as a record structure.
379 * Creates and caches strings.
382 asl_memory_message_encode(asl_memory_t
*s
, asl_msg_t
*msg
, mem_record_t
*r
)
387 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
388 if (msg
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
389 if (r
== NULL
) return ASL_STATUS_INVALID_ARG
;
391 memset(r
, 0, sizeof(mem_record_t
));
394 r
->level
= ASL_LEVEL_DEBUG
;
400 r
->time
= (uint64_t)-1;
401 r
->nano
= (uint32_t)-1;
403 for (i
= 0; i
< msg
->count
; i
++)
405 if (msg
->key
[i
] == NULL
) continue;
407 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
409 if (msg
->val
[i
] != NULL
) r
->time
= asl_parse_time(msg
->val
[i
]);
411 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME_NSEC
))
413 if (msg
->val
[i
] != NULL
) r
->nano
= atoi(msg
->val
[i
]);
415 else if (!strcmp(msg
->key
[i
], ASL_KEY_HOST
))
417 if (msg
->val
[i
] != NULL
) r
->host
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
419 else if (!strcmp(msg
->key
[i
], ASL_KEY_SENDER
))
421 if (msg
->val
[i
] != NULL
) r
->sender
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
423 else if (!strcmp(msg
->key
[i
], ASL_KEY_PID
))
425 if (msg
->val
[i
] != NULL
) r
->pid
= atoi(msg
->val
[i
]);
427 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PID
))
429 if (msg
->val
[i
] != NULL
) r
->refpid
= atoi(msg
->val
[i
]);
431 else if (!strcmp(msg
->key
[i
], ASL_KEY_UID
))
433 if (msg
->val
[i
] != NULL
) r
->uid
= atoi(msg
->val
[i
]);
435 else if (!strcmp(msg
->key
[i
], ASL_KEY_GID
))
437 if (msg
->val
[i
] != NULL
) r
->gid
= atoi(msg
->val
[i
]);
439 else if (!strcmp(msg
->key
[i
], ASL_KEY_LEVEL
))
441 if (msg
->val
[i
] != NULL
) r
->level
= atoi(msg
->val
[i
]);
443 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG
))
445 if (msg
->val
[i
] != NULL
) r
->message
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
447 else if (!strcmp(msg
->key
[i
], ASL_KEY_FACILITY
))
449 if (msg
->val
[i
] != NULL
) r
->facility
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
451 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PROC
))
453 if (msg
->val
[i
] != NULL
) r
->refproc
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
455 else if (!strcmp(msg
->key
[i
], ASL_KEY_SESSION
))
457 if (msg
->val
[i
] != NULL
) r
->session
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
459 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_UID
))
461 if (((r
->flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (msg
->val
[i
] != NULL
))
463 r
->ruid
= atoi(msg
->val
[i
]);
464 r
->flags
|= ASL_MSG_FLAG_READ_UID_SET
;
467 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_GID
))
469 if (((r
->flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (msg
->val
[i
] != NULL
))
471 r
->rgid
= atoi(msg
->val
[i
]);
472 r
->flags
|= ASL_MSG_FLAG_READ_GID_SET
;
475 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG_ID
))
482 k
= asl_memory_string_retain(s
, msg
->key
[i
], 1);
483 if (k
== NULL
) continue;
486 if (msg
->val
[i
] != NULL
) v
= asl_memory_string_retain(s
, msg
->val
[i
], 1);
490 r
->kvlist
= (mem_string_t
**)calloc(2, sizeof(mem_string_t
*));
494 r
->kvlist
= (mem_string_t
**)realloc(r
->kvlist
, (r
->kvcount
+ 2) * sizeof(mem_string_t
*));
497 if (r
->kvlist
== NULL
)
499 asl_memory_record_clear(s
, r
);
500 return ASL_STATUS_NO_MEMORY
;
503 r
->kvlist
[r
->kvcount
++] = k
;
504 r
->kvlist
[r
->kvcount
++] = v
;
508 return ASL_STATUS_OK
;
512 asl_memory_save(asl_memory_t
*s
, aslmsg msg
, uint64_t *mid
)
517 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
518 if (s
->buffer_record
== NULL
) return ASL_STATUS_INVALID_STORE
;
520 /* asl_memory_message_encode creates and caches strings */
521 status
= asl_memory_message_encode(s
, msg
, s
->buffer_record
);
522 if (status
!= ASL_STATUS_OK
) return status
;
526 s
->buffer_record
->mid
= *mid
;
530 s
->buffer_record
->mid
= asl_core_new_msg_id(0);
531 *mid
= s
->buffer_record
->mid
;
534 /* clear the first record */
535 t
= s
->record
[s
->record_first
];
536 asl_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;
550 * Decodes a record structure.
553 asl_memory_message_decode(asl_memory_t
*s
, mem_record_t
*r
, asl_msg_t
**out
)
558 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
559 if (r
== NULL
) return ASL_STATUS_INVALID_ARG
;
560 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
564 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
565 if (msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
567 msg
->type
= ASL_TYPE_MSG
;
568 /* Level and Message ID are always set */
570 if (r
->time
!= (uint64_t)-1) msg
->count
++;
571 if (r
->nano
!= (uint32_t)-1) msg
->count
++;
572 if (r
->host
!= NULL
) msg
->count
++;
573 if (r
->sender
!= NULL
) msg
->count
++;
574 if (r
->facility
!= NULL
) msg
->count
++;
575 if (r
->refproc
!= NULL
) msg
->count
++;
576 if (r
->session
!= NULL
) msg
->count
++;
577 if (r
->pid
!= -1) msg
->count
++;
578 if (r
->refpid
!= 0) msg
->count
++;
579 if (r
->uid
!= -2) msg
->count
++;
580 if (r
->gid
!= -2) msg
->count
++;
581 if (r
->message
!= NULL
) msg
->count
++;
582 if (r
->flags
& ASL_MSG_FLAG_READ_UID_SET
) msg
->count
++;
583 if (r
->flags
& ASL_MSG_FLAG_READ_GID_SET
) msg
->count
++;
585 msg
->count
+= (r
->kvcount
/ 2);
587 msg
->key
= (char **)calloc(msg
->count
, sizeof(char *));
588 if (msg
->key
== NULL
)
591 return ASL_STATUS_NO_MEMORY
;
594 msg
->val
= (char **)calloc(msg
->count
, sizeof(char *));
595 if (msg
->val
== NULL
)
599 return ASL_STATUS_NO_MEMORY
;
605 msg
->key
[n
] = strdup(ASL_KEY_MSG_ID
);
606 if (msg
->key
[n
] == NULL
)
609 return ASL_STATUS_NO_MEMORY
;
612 asprintf(&(msg
->val
[n
]), "%llu", r
->mid
);
613 if (msg
->val
[n
] == NULL
)
616 return ASL_STATUS_NO_MEMORY
;
621 msg
->key
[n
] = strdup(ASL_KEY_LEVEL
);
622 if (msg
->key
[n
] == NULL
)
625 return ASL_STATUS_NO_MEMORY
;
628 asprintf(&(msg
->val
[n
]), "%u", r
->level
);
629 if (msg
->val
[n
] == NULL
)
632 return ASL_STATUS_NO_MEMORY
;
637 if (r
->time
!= (uint64_t)-1)
639 msg
->key
[n
] = strdup(ASL_KEY_TIME
);
640 if (msg
->key
[n
] == NULL
)
643 return ASL_STATUS_NO_MEMORY
;
646 asprintf(&(msg
->val
[n
]), "%llu", r
->time
);
647 if (msg
->val
[n
] == NULL
)
650 return ASL_STATUS_NO_MEMORY
;
656 if (r
->nano
!= (uint32_t)-1)
658 msg
->key
[n
] = strdup(ASL_KEY_TIME_NSEC
);
659 if (msg
->key
[n
] == NULL
)
662 return ASL_STATUS_NO_MEMORY
;
665 asprintf(&(msg
->val
[n
]), "%lu", r
->nano
);
666 if (msg
->val
[n
] == NULL
)
669 return ASL_STATUS_NO_MEMORY
;
677 msg
->key
[n
] = strdup(ASL_KEY_HOST
);
678 if (msg
->key
[n
] == NULL
)
681 return ASL_STATUS_NO_MEMORY
;
684 msg
->val
[n
] = strdup(r
->host
->str
);
689 if (r
->sender
!= NULL
)
691 msg
->key
[n
] = strdup(ASL_KEY_SENDER
);
692 if (msg
->key
[n
] == NULL
)
695 return ASL_STATUS_NO_MEMORY
;
698 msg
->val
[n
] = strdup(r
->sender
->str
);
703 if (r
->facility
!= NULL
)
705 msg
->key
[n
] = strdup(ASL_KEY_FACILITY
);
706 if (msg
->key
[n
] == NULL
)
709 return ASL_STATUS_NO_MEMORY
;
712 msg
->val
[n
] = strdup(r
->facility
->str
);
717 if (r
->refproc
!= NULL
)
719 msg
->key
[n
] = strdup(ASL_KEY_REF_PROC
);
720 if (msg
->key
[n
] == NULL
)
723 return ASL_STATUS_NO_MEMORY
;
726 msg
->val
[n
] = strdup(r
->refproc
->str
);
731 if (r
->session
!= NULL
)
733 msg
->key
[n
] = strdup(ASL_KEY_SESSION
);
734 if (msg
->key
[n
] == NULL
)
737 return ASL_STATUS_NO_MEMORY
;
740 msg
->val
[n
] = strdup(r
->session
->str
);
747 msg
->key
[n
] = strdup(ASL_KEY_PID
);
748 if (msg
->key
[n
] == NULL
)
751 return ASL_STATUS_NO_MEMORY
;
754 asprintf(&(msg
->val
[n
]), "%d", r
->pid
);
755 if (msg
->val
[n
] == NULL
)
758 return ASL_STATUS_NO_MEMORY
;
766 msg
->key
[n
] = strdup(ASL_KEY_REF_PID
);
767 if (msg
->key
[n
] == NULL
)
770 return ASL_STATUS_NO_MEMORY
;
773 asprintf(&(msg
->val
[n
]), "%d", r
->refpid
);
774 if (msg
->val
[n
] == NULL
)
777 return ASL_STATUS_NO_MEMORY
;
785 msg
->key
[n
] = strdup(ASL_KEY_UID
);
786 if (msg
->key
[n
] == NULL
)
789 return ASL_STATUS_NO_MEMORY
;
792 asprintf(&(msg
->val
[n
]), "%d", r
->uid
);
793 if (msg
->val
[n
] == NULL
)
796 return ASL_STATUS_NO_MEMORY
;
804 msg
->key
[n
] = strdup(ASL_KEY_GID
);
805 if (msg
->key
[n
] == NULL
)
808 return ASL_STATUS_NO_MEMORY
;
811 asprintf(&(msg
->val
[n
]), "%d", r
->gid
);
812 if (msg
->val
[n
] == NULL
)
815 return ASL_STATUS_NO_MEMORY
;
821 if (r
->message
!= NULL
)
823 msg
->key
[n
] = strdup(ASL_KEY_MSG
);
824 if (msg
->key
[n
] == NULL
)
827 return ASL_STATUS_NO_MEMORY
;
830 msg
->val
[n
] = strdup(r
->message
->str
);
835 if (r
->flags
& ASL_MSG_FLAG_READ_UID_SET
)
837 msg
->key
[n
] = strdup(ASL_KEY_READ_UID
);
838 if (msg
->key
[n
] == NULL
)
841 return ASL_STATUS_NO_MEMORY
;
844 asprintf(&(msg
->val
[n
]), "%d", r
->ruid
);
845 if (msg
->val
[n
] == NULL
)
848 return ASL_STATUS_NO_MEMORY
;
854 if (r
->flags
& ASL_MSG_FLAG_READ_GID_SET
)
856 msg
->key
[n
] = strdup(ASL_KEY_READ_GID
);
857 if (msg
->key
[n
] == NULL
)
860 return ASL_STATUS_NO_MEMORY
;
863 asprintf(&(msg
->val
[n
]), "%d", r
->rgid
);
864 if (msg
->val
[n
] == NULL
)
867 return ASL_STATUS_NO_MEMORY
;
872 /* Key - Value List */
873 for (i
= 0; i
< r
->kvcount
; i
++)
875 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) msg
->key
[n
] = strdup(r
->kvlist
[i
]->str
);
877 if ((r
->kvlist
[i
] != NULL
) && (r
->kvlist
[i
]->str
!= NULL
)) msg
->val
[n
] = strdup(r
->kvlist
[i
]->str
);
882 return ASL_STATUS_OK
;
886 asl_memory_fetch(asl_memory_t
*s
, uint64_t mid
, aslmsg
*msg
, int32_t ruid
, int32_t rgid
)
890 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
891 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
893 for (i
= 0; i
< s
->record_count
; i
++)
895 if (s
->record
[i
]->mid
== 0) break;
897 if (s
->record
[i
]->mid
== mid
)
899 status
= asl_core_check_access(s
->record
[i
]->ruid
, s
->record
[i
]->rgid
, ruid
, rgid
, s
->record
[i
]->flags
);
900 if (status
!= ASL_STATUS_OK
) return status
;
901 return asl_memory_message_decode(s
, s
->record
[i
], msg
);
905 return ASL_STATUS_INVALID_ID
;
908 static mem_record_t
*
909 asl_memory_query_to_record(asl_memory_t
*s
, asl_msg_t
*q
, uint32_t *type
)
913 mem_string_t
*key
, *val
;
915 if (type
== NULL
) return NULL
;
919 *type
= ASL_QUERY_MATCH_ERROR
;
923 /* NULL query matches anything */
924 *type
= ASL_QUERY_MATCH_TRUE
;
925 if (q
== NULL
) return NULL
;
926 if (q
->count
== 0) return NULL
;
929 /* we can only do fast match on equality tests */
930 *type
= ASL_QUERY_MATCH_SLOW
;
933 for (i
= 0; i
< q
->count
; i
++) if (q
->op
[i
] != ASL_QUERY_OP_EQUAL
) return NULL
;
936 out
= (mem_record_t
*)calloc(1, sizeof(mem_record_t
));
939 *type
= ASL_QUERY_MATCH_ERROR
;
943 for (i
= 0; i
< q
->count
; i
++)
945 if (q
->key
[i
] == NULL
) continue;
947 else if (!strcmp(q
->key
[i
], ASL_KEY_MSG_ID
))
949 if (q
->val
[i
] == NULL
) continue;
951 if (*type
& ASL_QUERY_MATCH_MSG_ID
)
953 asl_memory_record_free(s
, out
);
954 *type
= ASL_QUERY_MATCH_SLOW
;
958 *type
|= ASL_QUERY_MATCH_MSG_ID
;
959 out
->mid
= atoll(q
->val
[i
]);
961 else if (!strcmp(q
->key
[i
], ASL_KEY_TIME
))
963 if (q
->val
[i
] == NULL
) continue;
965 if (*type
& ASL_QUERY_MATCH_TIME
)
967 asl_memory_record_free(s
, out
);
968 *type
= ASL_QUERY_MATCH_SLOW
;
972 *type
|= ASL_QUERY_MATCH_TIME
;
973 out
->time
= asl_parse_time(q
->val
[i
]);
975 else if (!strcmp(q
->key
[i
], ASL_KEY_TIME_NSEC
))
977 if (q
->val
[i
] == NULL
) continue;
979 if (*type
& ASL_QUERY_MATCH_NANO
)
981 asl_memory_record_free(s
, out
);
982 *type
= ASL_QUERY_MATCH_SLOW
;
986 *type
|= ASL_QUERY_MATCH_NANO
;
987 out
->nano
= atoll(q
->val
[i
]);
989 else if (!strcmp(q
->key
[i
], ASL_KEY_LEVEL
))
991 if (q
->val
[i
] == NULL
) continue;
993 if (*type
& ASL_QUERY_MATCH_LEVEL
)
995 asl_memory_record_free(s
, out
);
996 *type
= ASL_QUERY_MATCH_SLOW
;
1000 *type
|= ASL_QUERY_MATCH_LEVEL
;
1001 out
->level
= atoi(q
->val
[i
]);
1003 else if (!strcmp(q
->key
[i
], ASL_KEY_PID
))
1005 if (q
->val
[i
] == NULL
) continue;
1007 if (*type
& ASL_QUERY_MATCH_PID
)
1009 asl_memory_record_free(s
, out
);
1010 *type
= ASL_QUERY_MATCH_SLOW
;
1014 *type
|= ASL_QUERY_MATCH_PID
;
1015 out
->pid
= atoi(q
->val
[i
]);
1017 else if (!strcmp(q
->key
[i
], ASL_KEY_UID
))
1019 if (q
->val
[i
] == NULL
) continue;
1021 if (*type
& ASL_QUERY_MATCH_UID
)
1023 asl_memory_record_free(s
, out
);
1024 *type
= ASL_QUERY_MATCH_SLOW
;
1028 *type
|= ASL_QUERY_MATCH_UID
;
1029 out
->uid
= atoi(q
->val
[i
]);
1031 else if (!strcmp(q
->key
[i
], ASL_KEY_GID
))
1033 if (q
->val
[i
] == NULL
) continue;
1035 if (*type
& ASL_QUERY_MATCH_GID
)
1037 asl_memory_record_free(s
, out
);
1038 *type
= ASL_QUERY_MATCH_SLOW
;
1042 *type
|= ASL_QUERY_MATCH_GID
;
1043 out
->gid
= atoi(q
->val
[i
]);
1045 else if (!strcmp(q
->key
[i
], ASL_KEY_READ_UID
))
1047 if (q
->val
[i
] == NULL
) continue;
1049 if (*type
& ASL_QUERY_MATCH_RUID
)
1051 asl_memory_record_free(s
, out
);
1052 *type
= ASL_QUERY_MATCH_SLOW
;
1056 *type
|= ASL_QUERY_MATCH_RUID
;
1057 out
->ruid
= atoi(q
->val
[i
]);
1059 else if (!strcmp(q
->key
[i
], ASL_KEY_READ_GID
))
1061 if (q
->val
[i
] == NULL
) continue;
1063 if (*type
& ASL_QUERY_MATCH_RGID
)
1065 asl_memory_record_free(s
, out
);
1066 *type
= ASL_QUERY_MATCH_SLOW
;
1070 *type
|= ASL_QUERY_MATCH_RGID
;
1071 out
->rgid
= atoi(q
->val
[i
]);
1073 else if (!strcmp(q
->key
[i
], ASL_KEY_REF_PID
))
1075 if (q
->val
[i
] == NULL
) continue;
1077 if (*type
& ASL_QUERY_MATCH_REF_PID
)
1079 asl_memory_record_free(s
, out
);
1080 *type
= ASL_QUERY_MATCH_SLOW
;
1084 *type
|= ASL_QUERY_MATCH_REF_PID
;
1085 out
->refpid
= atoi(q
->val
[i
]);
1087 else if (!strcmp(q
->key
[i
], ASL_KEY_HOST
))
1089 if (q
->val
[i
] == NULL
) continue;
1091 if (*type
& ASL_QUERY_MATCH_HOST
)
1093 asl_memory_record_free(s
, out
);
1094 *type
= ASL_QUERY_MATCH_SLOW
;
1098 *type
|= ASL_QUERY_MATCH_HOST
;
1099 out
->host
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1100 if (out
->host
== NULL
)
1102 asl_memory_record_free(s
, out
);
1103 *type
= ASL_QUERY_MATCH_FALSE
;
1107 else if (!strcmp(q
->key
[i
], ASL_KEY_SENDER
))
1109 if (q
->val
[i
] == NULL
) continue;
1111 if (*type
& ASL_QUERY_MATCH_SENDER
)
1113 asl_memory_record_free(s
, out
);
1114 *type
= ASL_QUERY_MATCH_SLOW
;
1118 *type
|= ASL_QUERY_MATCH_SENDER
;
1119 out
->sender
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1120 if (out
->sender
== NULL
)
1122 asl_memory_record_free(s
, out
);
1123 *type
= ASL_QUERY_MATCH_FALSE
;
1127 else if (!strcmp(q
->key
[i
], ASL_KEY_FACILITY
))
1129 if (q
->val
[i
] == NULL
) continue;
1131 if (*type
& ASL_QUERY_MATCH_FACILITY
)
1133 asl_memory_record_free(s
, out
);
1134 *type
= ASL_QUERY_MATCH_SLOW
;
1138 *type
|= ASL_QUERY_MATCH_FACILITY
;
1139 out
->facility
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1140 if (out
->facility
== NULL
)
1142 asl_memory_record_free(s
, out
);
1143 *type
= ASL_QUERY_MATCH_FALSE
;
1147 else if (!strcmp(q
->key
[i
], ASL_KEY_MSG
))
1149 if (q
->val
[i
] == NULL
) continue;
1151 if (*type
& ASL_QUERY_MATCH_MESSAGE
)
1153 asl_memory_record_free(s
, out
);
1154 *type
= ASL_QUERY_MATCH_SLOW
;
1158 *type
|= ASL_QUERY_MATCH_MESSAGE
;
1159 out
->message
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1160 if (out
->message
== NULL
)
1162 asl_memory_record_free(s
, out
);
1163 *type
= ASL_QUERY_MATCH_FALSE
;
1167 else if (!strcmp(q
->key
[i
], ASL_KEY_REF_PROC
))
1169 if (q
->val
[i
] == NULL
) continue;
1171 if (*type
& ASL_QUERY_MATCH_REF_PROC
)
1173 asl_memory_record_free(s
, out
);
1174 *type
= ASL_QUERY_MATCH_SLOW
;
1178 *type
|= ASL_QUERY_MATCH_REF_PROC
;
1179 out
->refproc
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1180 if (out
->refproc
== NULL
)
1182 asl_memory_record_free(s
, out
);
1183 *type
= ASL_QUERY_MATCH_FALSE
;
1187 else if (!strcmp(q
->key
[i
], ASL_KEY_SESSION
))
1189 if (q
->val
[i
] == NULL
) continue;
1191 if (*type
& ASL_QUERY_MATCH_SESSION
)
1193 asl_memory_record_free(s
, out
);
1194 *type
= ASL_QUERY_MATCH_SLOW
;
1198 *type
|= ASL_QUERY_MATCH_SESSION
;
1199 out
->session
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1200 if (out
->session
== NULL
)
1202 asl_memory_record_free(s
, out
);
1203 *type
= ASL_QUERY_MATCH_FALSE
;
1209 key
= asl_memory_string_retain(s
, q
->key
[i
], 0);
1212 asl_memory_record_free(s
, out
);
1213 *type
= ASL_QUERY_MATCH_FALSE
;
1217 for (j
= 0; j
< out
->kvcount
; j
+= 2)
1219 if (out
->kvlist
[j
] == key
)
1221 asl_memory_record_free(s
, out
);
1222 *type
= ASL_QUERY_MATCH_SLOW
;
1227 val
= asl_memory_string_retain(s
, q
->val
[i
], 0);
1229 if (out
->kvcount
== 0)
1231 out
->kvlist
= (mem_string_t
**)calloc(2, sizeof(mem_string_t
*));
1235 out
->kvlist
= (mem_string_t
**)realloc(out
->kvlist
, (out
->kvcount
+ 2) * sizeof(mem_string_t
*));
1238 if (out
->kvlist
== NULL
)
1240 asl_memory_record_free(s
, out
);
1241 *type
= ASL_QUERY_MATCH_ERROR
;
1245 out
->kvlist
[out
->kvcount
++] = key
;
1246 out
->kvlist
[out
->kvcount
++] = val
;
1254 asl_memory_fast_match(asl_memory_t
*s
, mem_record_t
*r
, uint32_t qtype
, mem_record_t
*q
)
1258 if (s
== NULL
) return 0;
1259 if (r
== NULL
) return 0;
1260 if (q
== NULL
) return 1;
1262 if ((qtype
& ASL_QUERY_MATCH_MSG_ID
) && (q
->mid
!= r
->mid
)) return 0;
1263 if ((qtype
& ASL_QUERY_MATCH_TIME
) && (q
->time
!= r
->time
)) return 0;
1264 if ((qtype
& ASL_QUERY_MATCH_NANO
) && (q
->nano
!= r
->nano
)) return 0;
1265 if ((qtype
& ASL_QUERY_MATCH_LEVEL
) && (q
->level
!= r
->level
)) return 0;
1266 if ((qtype
& ASL_QUERY_MATCH_PID
) && (q
->pid
!= r
->pid
)) return 0;
1267 if ((qtype
& ASL_QUERY_MATCH_UID
) && (q
->uid
!= r
->uid
)) return 0;
1268 if ((qtype
& ASL_QUERY_MATCH_GID
) && (q
->gid
!= r
->gid
)) return 0;
1269 if ((qtype
& ASL_QUERY_MATCH_RUID
) && (q
->ruid
!= r
->ruid
)) return 0;
1270 if ((qtype
& ASL_QUERY_MATCH_RGID
) && (q
->rgid
!= r
->rgid
)) return 0;
1271 if ((qtype
& ASL_QUERY_MATCH_REF_PID
) && (q
->refpid
!= r
->refpid
)) return 0;
1272 if ((qtype
& ASL_QUERY_MATCH_HOST
) && (q
->host
!= r
->host
)) return 0;
1273 if ((qtype
& ASL_QUERY_MATCH_SENDER
) && (q
->sender
!= r
->sender
)) return 0;
1274 if ((qtype
& ASL_QUERY_MATCH_FACILITY
) && (q
->facility
!= r
->facility
)) return 0;
1275 if ((qtype
& ASL_QUERY_MATCH_MESSAGE
) && (q
->message
!= r
->message
)) return 0;
1276 if ((qtype
& ASL_QUERY_MATCH_REF_PROC
) && (q
->refproc
!= r
->refproc
)) return 0;
1277 if ((qtype
& ASL_QUERY_MATCH_SESSION
) && (q
->session
!= r
->session
)) return 0;
1279 for (i
= 0; i
< q
->kvcount
; i
+= 2)
1281 for (j
= 0; j
< r
->kvcount
; j
+= 2)
1283 if (q
->kvlist
[i
] == r
->kvlist
[j
])
1285 if (q
->kvlist
[i
+ 1] == r
->kvlist
[j
+ 1]) break;
1290 if (j
>= r
->kvcount
) return 0;
1297 asl_memory_slow_match(asl_memory_t
*s
, mem_record_t
*r
, mem_record_t
*q
, asl_msg_t
*rawq
)
1303 status
= asl_memory_message_decode(s
, r
, &rawm
);
1304 if (status
!= ASL_STATUS_OK
) return 0;
1307 if (asl_msg_cmp(rawq
, rawm
) != 0) status
= 1;
1313 asl_memory_match(asl_memory_t
*s
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
, int32_t ruid
, int32_t rgid
)
1315 uint32_t status
, i
, where
, start
, j
, do_match
, did_match
, rescount
, *qtype
;
1319 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1320 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1327 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0)))
1333 qp
= (mem_record_t
**)calloc(query
->count
, sizeof(mem_record_t
*));
1334 if (qp
== NULL
) return ASL_STATUS_NO_MEMORY
;
1336 qtype
= (uint32_t *)calloc(query
->count
, sizeof(uint32_t));
1340 return ASL_STATUS_NO_MEMORY
;
1344 for (i
= 0; i
< query
->count
; i
++)
1346 qp
[i
] = asl_memory_query_to_record(s
, query
->msg
[i
], &(qtype
[i
]));
1347 if (qtype
[i
] == ASL_QUERY_MATCH_ERROR
)
1349 for (j
= 0; j
< i
; j
++) asl_memory_record_free(s
, qp
[j
]);
1352 return ASL_STATUS_FAILED
;
1355 if (qtype
[i
] != ASL_QUERY_MATCH_TRUE
) do_match
= 1;
1359 for (i
= 0; i
< s
->record_count
; i
++)
1363 where
= (s
->record_first
+ i
) % s
->record_count
;
1364 if (s
->record
[where
]->mid
== 0) continue;
1365 if (s
->record
[where
]->mid
>= start_id
) break;
1369 where
= ((s
->record_count
- (i
+ 1)) + s
->record_first
) % s
->record_count
;
1370 if (s
->record
[where
]->mid
== 0) continue;
1371 if (s
->record
[where
]->mid
<= start_id
) break;
1375 if (i
>= s
->record_count
)
1379 for (i
= 0; i
< query
->count
; i
++) asl_memory_record_free(s
, qp
[i
]);
1384 return ASL_STATUS_OK
;
1390 * loop through records
1392 for (i
= 0; i
< s
->record_count
; i
++)
1394 status
= ASL_STATUS_INVALID_ID
;
1395 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
);
1396 if (status
!= ASL_STATUS_OK
)
1401 if (where
>= s
->record_count
) where
= 0;
1405 if (where
== 0) where
= s
->record_count
- 1;
1409 if (where
== s
->record_first
) break;
1413 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1414 *last_id
= s
->record
[where
]->mid
;
1421 for (j
= 0; (j
< query
->count
) && (did_match
== 0); j
++)
1423 if (qtype
[j
] == ASL_QUERY_MATCH_TRUE
)
1427 else if (qtype
[j
] == ASL_QUERY_MATCH_SLOW
)
1429 did_match
= asl_memory_slow_match(s
, s
->record
[where
], qp
[j
], query
->msg
[j
]);
1433 did_match
= asl_memory_fast_match(s
, s
->record
[where
], qtype
[j
], qp
[j
]);
1440 s
->record
[where
]->flags
|= ASL_MSG_FLAG_SEARCH_MATCH
;
1442 if ((count
!= 0) && (rescount
>= count
)) break;
1448 if (where
>= s
->record_count
) where
= 0;
1452 if (where
== 0) where
= s
->record_count
- 1;
1456 if (where
== s
->record_first
) break;
1461 for (i
= 0; i
< query
->count
; i
++) asl_memory_record_free(s
, qp
[i
]);
1467 if (rescount
== 0) return ASL_STATUS_OK
;
1469 *res
= (asl_msg_list_t
*)calloc(1, sizeof(asl_msg_list_t
));
1470 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1472 (*res
)->count
= rescount
;
1474 (*res
)->msg
= (asl_msg_t
**)calloc(rescount
, sizeof(asl_msg_t
*));
1475 if ((*res
)->msg
== NULL
)
1479 return ASL_STATUS_NO_MEMORY
;
1485 if (s
->record
[where
]->flags
& ASL_MSG_FLAG_SEARCH_MATCH
)
1487 s
->record
[where
]->flags
&= ASL_MSG_FLAG_SEARCH_CLEAR
;
1489 status
= asl_memory_message_decode(s
, s
->record
[where
], &m
);
1490 if (status
!= ASL_STATUS_OK
)
1492 aslresponse_free(*res
);
1497 (*res
)->msg
[(*res
)->curr
++] = m
;
1498 if ((*res
)->curr
== rescount
) break;
1504 if (where
>= s
->record_count
) where
= 0;
1508 if (where
== 0) where
= s
->record_count
- 1;
1512 if (where
== s
->record_first
) break;
1516 return ASL_STATUS_OK
;