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@
31 #include <sys/errno.h>
34 #include <sys/types.h>
36 #include <membership.h>
39 #include <asl_private.h>
40 #include <asl_legacy1.h>
42 extern time_t asl_parse_time(const char *str
);
43 extern int asl_msg_cmp(aslmsg a
, aslmsg b
);
45 #define forever for(;;)
46 #define MILLION 1000000
49 * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t)
50 * type and level are both 16 bit fields so that alignment isn't a pain.
52 #define RECORD_COMMON_LEN 6
53 #define RECORD_TYPE_LEN 2
54 #define BUFFER_OFFSET_KVCOUNT 56
56 #define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t)))
84 asl_file_list_t
*list
;
86 } asl_file_match_token_t
;
98 _asl_put_16(uint16_t i
, char *h
)
116 _asl_put_32(uint32_t i
, char *h
)
130 return asl_core_ntohq(x
);
134 _asl_put_64(uint64_t i
, char *h
)
138 x
= asl_core_htonq(i
);
143 asl_file_read_uint32(asl_file_t
*s
, off_t off
, uint32_t *out
)
145 uint32_t status
, val
;
147 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
148 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
149 if ((off
+ sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
151 status
= fseeko(s
->store
, off
, SEEK_SET
);
152 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
156 status
= fread(&val
, sizeof(uint32_t), 1, s
->store
);
157 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
159 if (out
!= NULL
) *out
= ntohl(val
);
160 return ASL_STATUS_OK
;
164 asl_file_read_uint64(asl_file_t
*s
, off_t off
, uint64_t *out
)
169 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
170 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
171 if ((off
+ sizeof(uint64_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
173 status
= fseeko(s
->store
, off
, SEEK_SET
);
174 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
178 status
= fread(&val
, sizeof(uint64_t), 1, s
->store
);
179 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
181 if (out
!= NULL
) *out
= asl_core_ntohq(val
);
182 return ASL_STATUS_OK
;
186 asl_file_close(asl_file_t
*s
)
190 if (s
== NULL
) return ASL_STATUS_OK
;
194 return asl_legacy1_close((asl_legacy1_t
*)s
->legacy
);
197 while (s
->string_list
!= NULL
)
199 x
= s
->string_list
->next
;
200 free(s
->string_list
);
204 if (s
->store
!= NULL
) fclose(s
->store
);
205 if (s
->scratch
!= NULL
) free(s
->scratch
);
207 memset(s
, 0, sizeof(asl_file_t
));
210 return ASL_STATUS_OK
;
213 __private_extern__
uint32_t
214 asl_file_open_write_fd(int fd
, asl_file_t
**s
)
218 char buf
[DB_HEADER_LEN
];
221 if (fd
< 0) return ASL_STATUS_FAILED
;
222 if (s
== NULL
) return ASL_STATUS_FAILED
;
224 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
225 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
227 out
->store
= fdopen(fd
, "w+");
228 if (out
->store
== NULL
)
231 return ASL_STATUS_FAILED
;
234 memset(buf
, 0, sizeof(buf
));
235 memcpy(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
);
237 _asl_put_32(DB_VERSION
, buf
+ DB_HEADER_VERS_OFFSET
);
241 _asl_put_64(out
->dob
, buf
+ DB_HEADER_TIME_OFFSET
);
243 _asl_put_32(CACHE_SIZE
, buf
+ DB_HEADER_CSIZE_OFFSET
);
245 status
= fwrite(buf
, sizeof(buf
), 1, out
->store
);
250 return ASL_STATUS_FAILED
;
256 out
->file_size
= sizeof(buf
);
258 /* scratch buffer for file writes (we test for NULL before using it) */
259 out
->scratch
= malloc(SCRATCH_BUFFER_SIZE
);
263 return ASL_STATUS_OK
;
266 __private_extern__
int
267 asl_file_create(const char *path
, uid_t uid
, gid_t gid
, mode_t mode
)
280 status
= mbr_gid_to_uuid(gid
, uuid
);
281 if (status
!= 0) goto asl_file_create_return
;
283 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
284 if (status
!= 0) goto asl_file_create_return
;
286 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
287 if (status
!= 0) goto asl_file_create_return
;
289 status
= acl_set_qualifier(entry
, &uuid
);
290 if (status
!= 0) goto asl_file_create_return
;
292 status
= acl_get_permset(entry
, &perms
);
293 if (status
!= 0) goto asl_file_create_return
;
295 status
= acl_add_perm(perms
, ACL_READ_DATA
);
296 if (status
!= 0) goto asl_file_create_return
;
301 status
= mbr_uid_to_uuid(uid
, uuid
);
302 if (status
!= 0) goto asl_file_create_return
;
304 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
305 if (status
!= 0) goto asl_file_create_return
;
307 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
308 if (status
!= 0) goto asl_file_create_return
;
310 status
= acl_set_qualifier(entry
, &uuid
);
311 if (status
!= 0) goto asl_file_create_return
;
313 status
= acl_get_permset(entry
, &perms
);
314 if (status
!= 0) goto asl_file_create_return
;
316 status
= acl_add_perm(perms
, ACL_READ_DATA
);
317 if (status
!= 0) goto asl_file_create_return
;
320 fd
= open(path
, O_RDWR
| O_CREAT
| O_EXCL
, mode
);
321 if (fd
< 0) goto asl_file_create_return
;
323 status
= acl_set_fd(fd
, acl
);
331 asl_file_create_return
:
338 asl_file_open_write(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, asl_file_t
**s
)
342 char buf
[DB_HEADER_LEN
];
344 uint32_t aslstatus
, vers
, last_len
;
347 memset(&sb
, 0, sizeof(struct stat
));
349 status
= stat(path
, &sb
);
352 /* must be a plain file */
353 if (!S_ISREG(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
357 fd
= open(path
, O_RDWR
| O_EXCL
, mode
);
358 if (fd
< 0) return ASL_STATUS_FAILED
;
360 return asl_file_open_write_fd(fd
, s
);
364 /* XXX Check that mode, uid, and gid are correct */
365 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
366 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
368 out
->store
= fopen(path
, "r+");
369 if (out
->store
== NULL
)
372 return ASL_STATUS_FAILED
;
375 i
= fread(buf
, DB_HEADER_LEN
, 1, out
->store
);
379 return ASL_STATUS_READ_FAILED
;
383 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
386 return ASL_STATUS_INVALID_STORE
;
390 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
391 if (vers
!= DB_VERSION
)
394 return ASL_STATUS_INVALID_STORE
;
397 out
->dob
= _asl_get_64(buf
+ DB_HEADER_TIME_OFFSET
);
398 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
399 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
400 out
->file_size
= (size_t)sb
.st_size
;
403 * Detect bogus last pointer and check for odd-sized files.
404 * Setting out->last to zero forces asl_file_read_set_position to
405 * follow the linked list of records in the file to the last record.
406 * It's slower, but it's better at preventing crashes in corrupt files.
409 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
410 if ((out
->last
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
)
416 /* read last record length and make sure the file is at least that large */
417 off
= out
->last
+ RECORD_TYPE_LEN
;
418 status
= asl_file_read_uint32(out
, off
, &last_len
);
419 if (status
!= ASL_STATUS_OK
)
425 if ((out
->last
+ last_len
) > out
->file_size
) out
->last
= 0;
428 aslstatus
= asl_file_read_set_position(out
, ASL_FILE_POSITION_LAST
);
429 if (aslstatus
!= ASL_STATUS_OK
)
435 out
->prev
= out
->cursor
;
436 status
= fseeko(out
->store
, 0, SEEK_END
);
440 return ASL_STATUS_READ_FAILED
;
443 out
->file_size
= (size_t)ftello(out
->store
);
445 /* scratch buffer for file writes (we test for NULL before using it) */
446 out
->scratch
= malloc(SCRATCH_BUFFER_SIZE
);
450 return ASL_STATUS_OK
;
453 else if (errno
!= ENOENT
)
455 /* unexpected status */
456 return ASL_STATUS_FAILED
;
459 /* the file does not exist */
460 fd
= asl_file_create(path
, uid
, gid
, mode
);
461 if (fd
< 0) return ASL_STATUS_FAILED
;
463 aslstatus
= asl_file_open_write_fd(fd
, s
);
464 if (aslstatus
!= ASL_STATUS_OK
) unlink(path
);
470 asl_file_compact(asl_file_t
*s
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
478 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
479 if (path
== NULL
) return ASL_STATUS_INVALID_ARG
;
481 if (s
->version
== 1) return ASL_STATUS_FAILED
;
483 memset(&sb
, 0, sizeof(struct stat
));
485 if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
;
486 if (errno
!= ENOENT
) return ASL_STATUS_FAILED
;
488 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
489 if (status
!= ASL_STATUS_OK
) return status
;
492 status
= asl_file_open_write(path
, mode
, uid
, gid
, &new);
493 if (status
!= ASL_STATUS_OK
) return status
;
494 new->flags
= ASL_FILE_FLAG_UNLIMITED_CACHE
| ASL_FILE_FLAG_PRESERVE_MSG_ID
;
496 while ((status
== ASL_STATUS_OK
) && (s
->cursor
!= 0))
499 status
= asl_file_fetch_next(s
, &m
);
500 if (status
!= ASL_STATUS_OK
) break;
503 status
= asl_file_save(new, m
, &xid
);
512 asl_file_string_encode(asl_file_t
*s
, const char *str
, uint64_t *out
)
514 uint32_t i
, hash
, len
, x32
;
515 file_string_t
*sp
, *sx
, *sl
;
522 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
523 if (str
== NULL
) return ASL_STATUS_INVALID_ARG
;
537 memcpy(p
+ 1, str
, len
);
538 *out
= asl_core_ntohq(x64
);
539 return ASL_STATUS_OK
;
542 /* check the cache */
543 hash
= asl_core_string_hash(str
, len
);
546 for (sx
= s
->string_list
; sx
!= NULL
; sx
= sx
->next
)
548 if ((hash
== sx
->hash
) && (!strcmp(str
, sx
->str
)))
550 /* Move this string to the head of the list */
560 return ASL_STATUS_OK
;
566 off
= ftello(s
->store
);
569 type
= htons(ASL_FILE_TYPE_STR
);
570 i
= fwrite(&type
, sizeof(uint16_t), 1, s
->store
);
571 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
573 /* Length (includes trailing nul) */
574 x32
= htonl(len
+ 1);
575 i
= fwrite(&x32
, sizeof(uint32_t), 1, s
->store
);
576 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
578 /* String data (nul terminated) */
579 i
= fwrite(str
, len
+ 1, 1, s
->store
);
580 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
585 /* create file_string_t and insert into the cache */
586 sx
= (file_string_t
*)calloc(1, offsetof(file_string_t
, str
) + len
+ 1);
587 if (sx
== NULL
) return ASL_STATUS_NO_MEMORY
;
591 sx
->next
= s
->string_list
;
592 memcpy(sx
->str
, str
, len
);
596 if (((s
->flags
& ASL_FILE_FLAG_UNLIMITED_CACHE
) == 0) && (s
->string_count
== CACHE_SIZE
))
598 /* drop last (lru) string from cache */
602 /* NB CACHE_SIZE must be > 1 */
603 while (sx
->next
!= NULL
)
618 return ASL_STATUS_OK
;
622 * Encode an aslmsg as a record structure.
623 * Creates and caches strings.
626 asl_file_save(asl_file_t
*s
, aslmsg in
, uint64_t *mid
)
629 uint32_t i
, len
, x
, status
;
635 const char *key
, *val
;
637 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
638 if (in
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
640 if (s
->flags
& ASL_FILE_FLAG_READ_ONLY
) return ASL_STATUS_READ_ONLY
;
642 msg
= (asl_msg_t
*)in
;
644 memset(&r
, 0, sizeof(file_record_t
));
647 r
.level
= ASL_LEVEL_DEBUG
;
661 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
667 else if (!strcmp(key
, ASL_KEY_TIME
))
669 if (val
!= NULL
) r
.time
= asl_parse_time(val
);
671 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
673 if (val
!= NULL
) r
.nano
= atoi(val
);
675 else if (!strcmp(key
, ASL_KEY_HOST
))
679 status
= asl_file_string_encode(s
, val
, &(r
.host
));
680 if (status
!= ASL_STATUS_OK
)
682 if (kvlist
!= NULL
) free(kvlist
);
687 else if (!strcmp(key
, ASL_KEY_SENDER
))
691 status
= asl_file_string_encode(s
, val
, &(r
.sender
));
692 if (status
!= ASL_STATUS_OK
)
694 if (kvlist
!= NULL
) free(kvlist
);
699 else if (!strcmp(key
, ASL_KEY_PID
))
701 if (val
!= NULL
) r
.pid
= atoi(val
);
703 else if (!strcmp(key
, ASL_KEY_REF_PID
))
705 if (val
!= NULL
) r
.refpid
= atoi(val
);
707 else if (!strcmp(key
, ASL_KEY_UID
))
709 if (val
!= NULL
) r
.uid
= atoi(val
);
711 else if (!strcmp(key
, ASL_KEY_GID
))
713 if (val
!= NULL
) r
.gid
= atoi(val
);
715 else if (!strcmp(key
, ASL_KEY_LEVEL
))
717 if (val
!= NULL
) r
.level
= atoi(val
);
719 else if (!strcmp(key
, ASL_KEY_MSG
))
723 status
= asl_file_string_encode(s
, val
, &(r
.message
));
724 if (status
!= ASL_STATUS_OK
)
726 if (kvlist
!= NULL
) free(kvlist
);
731 else if (!strcmp(key
, ASL_KEY_FACILITY
))
735 status
= asl_file_string_encode(s
, val
, &(r
.facility
));
736 if (status
!= ASL_STATUS_OK
)
738 if (kvlist
!= NULL
) free(kvlist
);
743 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
747 status
= asl_file_string_encode(s
, val
, &(r
.refproc
));
748 if (status
!= ASL_STATUS_OK
)
750 if (kvlist
!= NULL
) free(kvlist
);
755 else if (!strcmp(key
, ASL_KEY_SESSION
))
759 status
= asl_file_string_encode(s
, val
, &(r
.session
));
760 if (status
!= ASL_STATUS_OK
)
762 if (kvlist
!= NULL
) free(kvlist
);
767 else if (!strcmp(key
, ASL_KEY_READ_UID
))
769 if (((r
.flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (val
!= NULL
))
772 r
.flags
|= ASL_MSG_FLAG_READ_UID_SET
;
775 else if (!strcmp(key
, ASL_KEY_READ_GID
))
777 if (((r
.flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (val
!= NULL
))
780 r
.flags
|= ASL_MSG_FLAG_READ_GID_SET
;
783 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
785 if (s
->flags
& ASL_FILE_FLAG_PRESERVE_MSG_ID
) *mid
= atoll(val
);
787 else if (!strcmp(key
, ASL_KEY_OPTION
))
789 /* ignore - we don't save ASLOption */
793 status
= asl_file_string_encode(s
, key
, &k
);
794 if (status
!= ASL_STATUS_OK
)
796 if (kvlist
!= NULL
) free(kvlist
);
803 status
= asl_file_string_encode(s
, val
, &v
);
804 if (status
!= ASL_STATUS_OK
)
806 if (kvlist
!= NULL
) free(kvlist
);
813 kvlist
= (uint64_t *)calloc(2, sizeof(uint64_t));
817 kvlist
= (uint64_t *)reallocf(kvlist
, (r
.kvcount
+ 2) * sizeof(uint64_t));
822 return ASL_STATUS_NO_MEMORY
;
825 kvlist
[r
.kvcount
++] = k
;
826 kvlist
[r
.kvcount
++] = v
;
830 len
= MSG_RECORD_FIXED_LENGTH
+ (r
.kvcount
* sizeof(uint64_t));
833 /* use the scratch buffer if it exists and is large enough */
834 if ((s
->scratch
!= NULL
) && (len
<= SCRATCH_BUFFER_SIZE
))
836 memset(s
->scratch
, 0, SCRATCH_BUFFER_SIZE
);
841 buf
= calloc(1, len
);
844 if (buf
== NULL
) return ASL_STATUS_NO_MEMORY
;
852 r
.mid
= asl_core_new_msg_id(0);
859 _asl_put_16(ASL_FILE_TYPE_MSG
, p
);
860 p
+= sizeof(uint16_t);
862 /* Length of message (excludes type and length fields) */
863 _asl_put_32(len
- RECORD_COMMON_LEN
, p
);
864 p
+= sizeof(uint32_t);
866 /* Message data... */
868 _asl_put_64(r
.next
, p
);
869 p
+= sizeof(uint64_t);
871 _asl_put_64(r
.mid
, p
);
872 p
+= sizeof(uint64_t);
874 _asl_put_64(r
.time
, p
);
875 p
+= sizeof(uint64_t);
877 _asl_put_32(r
.nano
, p
);
878 p
+= sizeof(uint32_t);
880 _asl_put_16(r
.level
, p
);
881 p
+= sizeof(uint16_t);
883 _asl_put_16(r
.flags
, p
);
884 p
+= sizeof(uint16_t);
886 _asl_put_32(r
.pid
, p
);
887 p
+= sizeof(uint32_t);
889 _asl_put_32(r
.uid
, p
);
890 p
+= sizeof(uint32_t);
892 _asl_put_32(r
.gid
, p
);
893 p
+= sizeof(uint32_t);
895 _asl_put_32(r
.ruid
, p
);
896 p
+= sizeof(uint32_t);
898 _asl_put_32(r
.rgid
, p
);
899 p
+= sizeof(uint32_t);
901 _asl_put_32(r
.refpid
, p
);
902 p
+= sizeof(uint32_t);
904 _asl_put_32(r
.kvcount
, p
);
905 p
+= sizeof(uint32_t);
907 _asl_put_64(r
.host
, p
);
908 p
+= sizeof(uint64_t);
910 _asl_put_64(r
.sender
, p
);
911 p
+= sizeof(uint64_t);
913 _asl_put_64(r
.facility
, p
);
914 p
+= sizeof(uint64_t);
916 _asl_put_64(r
.message
, p
);
917 p
+= sizeof(uint64_t);
919 _asl_put_64(r
.refproc
, p
);
920 p
+= sizeof(uint64_t);
922 _asl_put_64(r
.session
, p
);
923 p
+= sizeof(uint64_t);
925 for (i
= 0; i
< r
.kvcount
; i
++)
927 _asl_put_64(kvlist
[i
], p
);
928 p
+= sizeof(uint64_t);
931 _asl_put_64(r
.prev
, p
);
932 p
+= sizeof(uint64_t);
937 /* write record at end of file */
938 status
= fseeko(s
->store
, 0, SEEK_END
);
939 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
941 s
->last
= (uint64_t)ftello(s
->store
);
943 v
= asl_core_htonq(s
->last
);
945 status
= fwrite(buf
, len
, 1, s
->store
);
948 /* free the buffer if it was allocated here */
949 if (buf
!= s
->scratch
) free(buf
);
951 /* seek to "next" field of previous record, write last offset */
952 off
= s
->prev
+ RECORD_COMMON_LEN
;
953 if (s
->prev
== 0) off
= DB_HEADER_FIRST_OFFSET
;
955 status
= fseeko(s
->store
, off
, SEEK_SET
);
956 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
958 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
959 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
961 /* seek to DB_HEADER_LAST_OFFSET, write last record offset */
962 off
= DB_HEADER_LAST_OFFSET
;
964 status
= fseeko(s
->store
, off
, SEEK_SET
);
965 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
967 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
968 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
970 /* return to the end of the store (this is expected by other routines) */
971 status
= fseeko(s
->store
, 0, SEEK_END
);
972 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
977 s
->file_size
= (size_t)ftello(s
->store
);
981 return ASL_STATUS_OK
;
985 asl_file_fetch_object(asl_file_t
*s
, uint64_t where
, char **out
, uint32_t *outlen
)
999 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1000 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
1001 if (where
== 0) return ASL_STATUS_INVALID_ARG
;
1004 x64
= asl_core_htonq(where
);
1005 memcpy(&inls
, &x64
, 1);
1010 if (inls
> 7) return ASL_STATUS_INVALID_STORE
;
1012 p
= 1 + (char *)&x64
;
1013 memset(ils
, 0, sizeof(ils
));
1014 memcpy(ils
, p
, inls
);
1016 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1019 return ASL_STATUS_OK
;
1023 if ((off
+ sizeof(uint16_t) + sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
1025 status
= fseeko(s
->store
, off
, SEEK_SET
);
1026 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
1029 status
= fread(&type
, sizeof(uint16_t), 1, s
->store
);
1030 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
1031 off
+= sizeof(uint16_t);
1035 status
= fread(&len
, sizeof(uint32_t), 1, s
->store
);
1036 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
1037 off
+= sizeof(uint32_t);
1040 if ((off
+ len
) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
1042 *out
= calloc(1, len
);
1043 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1045 status
= fread(*out
, len
, 1, s
->store
);
1049 return ASL_STATUS_READ_FAILED
;
1053 return ASL_STATUS_OK
;
1057 asl_file_fetch_helper_16(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
1062 out
= _asl_get_16(*p
);
1063 *p
+= sizeof(uint16_t);
1065 if ((m
== NULL
) || (key
== NULL
)) return out
;
1067 snprintf(str
, sizeof(str
), "%hu", out
);
1068 asl_set(m
, key
, str
);
1074 asl_file_fetch_helper_32(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, int ignore
, uint32_t ignoreval
)
1079 out
= _asl_get_32(*p
);
1080 *p
+= sizeof(uint32_t);
1082 if ((m
== NULL
) || (key
== NULL
)) return out
;
1085 if ((ignore
!= 0) && (out
== ignoreval
)) doit
= 0;
1088 snprintf(str
, sizeof(str
), "%u", out
);
1089 asl_set(m
, key
, str
);
1096 asl_file_fetch_helper_64(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
1101 out
= _asl_get_64(*p
);
1102 *p
+= sizeof(uint64_t);
1104 if ((m
== NULL
) || (key
== NULL
)) return out
;
1106 snprintf(str
, sizeof(str
), "%llu", out
);
1107 asl_set(m
, key
, str
);
1113 asl_file_fetch_helper_str(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, uint32_t *err
)
1117 uint32_t status
, len
;
1119 out
= _asl_get_64(*p
);
1120 *p
+= sizeof(uint64_t);
1124 status
= ASL_STATUS_OK
;
1125 if (out
!= 0) status
= asl_file_fetch_object(s
, out
, &val
, &len
);
1127 if (err
!= NULL
) *err
= status
;
1128 if ((status
== ASL_STATUS_OK
) && (val
!= NULL
))
1130 asl_set(m
, key
, val
);
1138 asl_file_fetch_pos(asl_file_t
*s
, uint64_t where
, int dir
, aslmsg
*msg
)
1140 char *buf
, *p
, *k
, *v
;
1142 uint32_t i
, status
, len
, buflen
, kvn
;
1147 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1148 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1149 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1153 status
= asl_file_fetch_object(s
, where
, &buf
, &buflen
);
1154 if ((status
!= ASL_STATUS_OK
) || (buf
== NULL
))
1161 /* check buffer size */
1162 kvn
= _asl_get_32(buf
+ BUFFER_OFFSET_KVCOUNT
);
1163 if (buflen
< (MSG_RECORD_FIXED_LENGTH
- RECORD_COMMON_LEN
+ (kvn
* sizeof(uint64_t))))
1168 return ASL_STATUS_READ_FAILED
;
1171 out
= asl_new(ASL_TYPE_MSG
);
1172 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1174 memset(&r
, 0, sizeof(file_record_t
));
1177 r
.next
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
);
1178 r
.mid
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_MSG_ID
);
1179 r
.time
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_TIME
);
1180 r
.nano
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_TIME_NSEC
, 0, 0);
1181 r
.level
= asl_file_fetch_helper_16(s
, &p
, out
, ASL_KEY_LEVEL
);
1182 r
.flags
= asl_file_fetch_helper_16(s
, &p
, NULL
, NULL
);
1183 r
.pid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_PID
, 0, 0);
1184 r
.uid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_UID
, 1, (uint32_t)-1);
1185 r
.gid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_GID
, 1, (uint32_t)-1);
1186 r
.ruid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_UID
, 1, (uint32_t)-1);
1187 r
.rgid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_GID
, 1, (uint32_t)-1);
1188 r
.refpid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_REF_PID
, 1, 0);
1189 r
.kvcount
= asl_file_fetch_helper_32(s
, &p
, NULL
, NULL
, 0, 0);
1191 status
= ASL_STATUS_OK
;
1192 r
.host
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_HOST
, &status
); /* 68 */
1193 if (status
== ASL_STATUS_OK
) r
.sender
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SENDER
, &status
); /* 76 */
1194 if (status
== ASL_STATUS_OK
) r
.facility
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_FACILITY
, &status
); /* 84 */
1195 if (status
== ASL_STATUS_OK
) r
.message
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_MSG
, &status
); /* 92 */
1196 if (status
== ASL_STATUS_OK
) r
.refproc
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_REF_PROC
, &status
); /* 100 */
1197 if (status
== ASL_STATUS_OK
) r
.session
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SESSION
, &status
); /* 108 */
1199 if (status
!= ASL_STATUS_OK
)
1208 kvn
= r
.kvcount
/ 2;
1210 for (i
= 0; i
< kvn
; i
++)
1212 kv
= _asl_get_64(p
);
1213 p
+= sizeof(uint64_t);
1216 status
= asl_file_fetch_object(s
, kv
, &k
, &len
);
1217 if (status
!= ASL_STATUS_OK
)
1226 kv
= _asl_get_64(p
);
1227 p
+= sizeof(uint64_t);
1233 status
= asl_file_fetch_object(s
, kv
, &v
, &len
);
1234 if (status
!= ASL_STATUS_OK
)
1244 if ((status
== ASL_STATUS_OK
) && (k
!= NULL
))
1247 if (v
!= NULL
) free(v
);
1252 r
.prev
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
); /* 116 */
1256 if (dir
>= 0) s
->cursor
= r
.next
;
1257 else s
->cursor
= r
.prev
;
1263 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1264 if (off
> s
->file_size
)
1270 * Next record offset is past the end of the file.
1271 * This is an error, but we allow it to fail quietly
1272 * so that the current record fetch succeeds.
1274 return ASL_STATUS_OK
;
1277 status
= fseeko(s
->store
, off
, SEEK_SET
);
1283 return ASL_STATUS_READ_FAILED
;
1286 status
= fread(&x64
, sizeof(uint64_t), 1, s
->store
);
1292 return ASL_STATUS_READ_FAILED
;
1295 s
->cursor_xid
= asl_core_ntohq(x64
);
1299 return ASL_STATUS_OK
;
1303 asl_file_open_read(const char *path
, asl_file_t
**s
)
1308 uint32_t status
, vers
, last_len
;
1309 char buf
[DB_HEADER_LEN
];
1311 asl_legacy1_t
*legacy
;
1314 memset(&sb
, 0, sizeof(struct stat
));
1315 if (stat(path
, &sb
) != 0) return ASL_STATUS_FAILED
;
1317 f
= fopen(path
, "r");
1320 if (errno
== EACCES
) return ASL_STATUS_ACCESS_DENIED
;
1321 return ASL_STATUS_FAILED
;
1324 i
= fread(buf
, DB_HEADER_LEN
, 1, f
);
1328 return ASL_STATUS_INVALID_STORE
;
1331 /* validate header */
1332 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
1335 return ASL_STATUS_INVALID_STORE
;
1340 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
1341 if (vers
== DB_VERSION_LEGACY_1
)
1344 status
= asl_legacy1_open(path
, &legacy
);
1345 if (status
!= ASL_STATUS_OK
) return status
;
1348 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
1352 return ASL_STATUS_NO_MEMORY
;
1356 out
->flags
= ASL_FILE_FLAG_READ_ONLY
;
1357 out
->version
= vers
;
1361 out
->flags
|= ASL_FILE_FLAG_LEGACY_STORE
;
1362 out
->legacy
= (void *)legacy
;
1365 return ASL_STATUS_OK
;
1368 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
1369 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
1370 out
->file_size
= (size_t)sb
.st_size
;
1373 * Detect bogus last pointer and check for odd-sized files.
1374 * Setting out->last to zero forces us to follow the linked
1375 * list of records in the file to the last record. That's
1376 * done in the set_position code. It's a bit slower, but it's
1377 * better at preventing crashes in corrupt files.
1380 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
1381 if ((out
->last
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
)
1387 /* read last record length and make sure the file is at least that large */
1388 off
= out
->last
+ RECORD_TYPE_LEN
;
1389 status
= asl_file_read_uint32(out
, off
, &last_len
);
1390 if (status
!= ASL_STATUS_OK
)
1397 if ((out
->last
+ last_len
) > out
->file_size
) out
->last
= 0;
1400 out
->cursor
= out
->first
;
1401 if (out
->cursor
!= 0)
1403 off
= out
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1404 status
= asl_file_read_uint64(out
, off
, &(out
->cursor_xid
));
1405 if (status
!= ASL_STATUS_OK
)
1414 return ASL_STATUS_OK
;
1418 asl_file_read_set_position_first(asl_file_t
*s
)
1423 s
->cursor
= s
->first
;
1426 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1428 /* read ID of the first record */
1429 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1430 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1435 asl_file_read_set_position_last(asl_file_t
*s
)
1442 * If the file has the offset of the last record, we just go there.
1443 * The last record offset was added to improve performance, so it may
1444 * or may not be there. If we don't have the last record offset, we
1445 * just iterate down the record links to find the last one.
1447 * Note that s->last may be zero if the file is empty.
1452 s
->cursor
= s
->last
;
1453 off
= s
->last
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1455 /* read ID of the last record */
1456 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1460 /* start at the first record and iterate */
1461 s
->cursor
= s
->first
;
1466 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1469 /* read next offset */
1470 status
= asl_file_read_uint64(s
, off
, &next
);
1471 if (status
!= ASL_STATUS_OK
) return status
;
1473 /* detect bogus next pointer */
1474 if (((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) || (next
<= s
->cursor
)) next
= 0;
1478 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1480 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1481 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1482 return ASL_STATUS_OK
;
1490 asl_file_read_set_position(asl_file_t
*s
, uint32_t pos
)
1493 uint32_t len
, status
;
1496 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1497 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1499 if (pos
== ASL_FILE_POSITION_FIRST
) return asl_file_read_set_position_first(s
);
1500 if (pos
== ASL_FILE_POSITION_LAST
) return asl_file_read_set_position_last(s
);
1504 if (pos
== ASL_FILE_POSITION_PREVIOUS
)
1506 if (s
->cursor
== s
->first
) return ASL_STATUS_NO_RECORDS
;
1507 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1509 off
= s
->cursor
+ RECORD_TYPE_LEN
;
1510 status
= asl_file_read_uint32(s
, off
, &len
);
1511 if (status
!= ASL_STATUS_OK
) return status
;
1513 /* set offset to read the "previous" field at the end of the record */
1514 off
= s
->cursor
+ RECORD_COMMON_LEN
+ len
- sizeof(uint64_t);
1516 else if (pos
== ASL_FILE_POSITION_NEXT
)
1518 if (s
->cursor
== s
->last
) return ASL_STATUS_NO_RECORDS
;
1519 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1521 /* set offset to read the "next" field in the current record */
1522 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1524 else return ASL_STATUS_INVALID_ARG
;
1529 * read offset of next / previous
1532 status
= asl_file_read_uint64(s
, off
, &next
);
1533 if (status
!= ASL_STATUS_OK
) return ASL_STATUS_READ_FAILED
;
1535 /* detect bogus next pointer */
1536 if ((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) next
= 0;
1537 else if ((pos
== ASL_FILE_POSITION_PREVIOUS
) && (next
>= s
->cursor
)) next
= 0;
1538 else if ((pos
== ASL_FILE_POSITION_NEXT
) && (next
<= s
->cursor
)) next
= 0;
1541 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1543 /* read ID of the record */
1544 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1545 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1550 asl_file_fetch_next(asl_file_t
*s
, aslmsg
*msg
)
1552 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1553 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1555 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1559 asl_file_fetch_previous(asl_file_t
*s
, aslmsg
*msg
)
1561 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1562 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1564 return asl_file_fetch_pos(s
, s
->cursor
, -1, msg
);
1568 asl_file_fetch(asl_file_t
*s
, uint64_t mid
, aslmsg
*msg
)
1572 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1573 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1574 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1576 if (s
->version
== 1)
1578 return asl_legacy1_fetch((asl_legacy1_t
*)s
->legacy
, mid
, msg
);
1581 if (s
->cursor_xid
== 0)
1583 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1584 if (status
!= ASL_STATUS_OK
) return status
;
1585 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1588 while (s
->cursor_xid
< mid
)
1590 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_NEXT
);
1591 if (status
!= ASL_STATUS_OK
) return status
;
1592 if (s
->cursor_xid
> mid
) return ASL_STATUS_INVALID_ID
;
1593 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1596 while (s
->cursor_xid
> mid
)
1598 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_PREVIOUS
);
1599 if (status
!= ASL_STATUS_OK
) return status
;
1600 if (s
->cursor_xid
< mid
) return ASL_STATUS_INVALID_ID
;
1601 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1604 if (s
->cursor_xid
!= mid
) return ASL_STATUS_INVALID_ID
;
1606 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1609 __private_extern__
uint64_t
1610 asl_file_cursor(asl_file_t
*s
)
1612 if (s
== NULL
) return 0;
1613 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return 0;
1614 if (s
->version
== 1) return 0;
1616 return s
->cursor_xid
;
1619 __private_extern__
uint32_t
1620 asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
)
1624 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1625 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1626 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1628 d
= ASL_FILE_POSITION_NEXT
;
1629 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1632 * find starting point
1634 status
= ASL_STATUS_OK
;
1635 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1636 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1637 if (status
!= ASL_STATUS_OK
) return status
;
1639 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1641 status
= asl_file_read_set_position(s
, d
);
1647 __private_extern__
uint32_t
1648 asl_file_match_next(asl_file_t
*s
, aslresponse query
, aslmsg
*msg
, uint64_t *last_id
, int32_t direction
)
1650 uint32_t status
, d
, i
, do_match
, did_match
;
1653 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1654 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1655 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1656 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1657 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1662 d
= ASL_FILE_POSITION_NEXT
;
1663 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1665 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1669 *last_id
= s
->cursor_xid
;
1671 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1672 if (status
== ASL_STATUS_ACCESS_DENIED
) return ASL_STATUS_MATCH_FAILED
;
1673 if ((status
== ASL_STATUS_INVALID_ARG
) && (s
->cursor
== 0)) return ASL_STATUS_NO_RECORDS
;
1674 if (status
!= ASL_STATUS_OK
) return status
;
1682 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1684 did_match
= asl_msg_cmp((aslmsg
)(query
->msg
[i
]), m
);
1691 return ASL_STATUS_OK
;
1695 return ASL_STATUS_MATCH_FAILED
;
1699 asl_file_match(asl_file_t
*s
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
1701 uint32_t status
, d
, i
, do_match
, did_match
, rescount
;
1704 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1705 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1706 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1708 if (s
->version
== 1)
1710 return asl_legacy1_match((asl_legacy1_t
*)s
->legacy
, query
, res
, last_id
, start_id
, count
, direction
);
1716 d
= ASL_FILE_POSITION_NEXT
;
1717 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1719 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1722 * find starting point
1724 status
= ASL_STATUS_OK
;
1725 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1726 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1727 if (status
!= ASL_STATUS_OK
) return status
;
1729 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1731 status
= asl_file_read_set_position(s
, d
);
1735 * loop through records
1740 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1741 if (status
== ASL_STATUS_ACCESS_DENIED
) continue;
1742 if (status
!= ASL_STATUS_OK
) break;
1744 *last_id
= s
->cursor_xid
;
1752 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1754 did_match
= asl_msg_cmp((aslmsg
)query
->msg
[i
], m
);
1760 /* append m to res */
1763 *res
= (aslresponse
)calloc(1, sizeof(aslresponse
));
1764 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1765 (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1766 if ((*res
)->msg
== NULL
)
1769 return ASL_STATUS_NO_MEMORY
;
1774 (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1775 if ((*res
)->msg
== NULL
)
1778 return ASL_STATUS_NO_MEMORY
;
1782 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
1786 if ((count
!= 0) && (rescount
>= count
)) break;
1795 return ASL_STATUS_OK
;
1799 asl_file_size(asl_file_t
*s
)
1801 if (s
== NULL
) return 0;
1802 return s
->file_size
;
1806 asl_file_ctime(asl_file_t
*s
)
1808 if (s
== NULL
) return 0;
1813 asl_file_list_close(asl_file_list_t
*head
)
1815 asl_file_list_t
*next
;
1817 while (head
!= NULL
)
1820 asl_file_close(head
->file
);
1827 asl_file_list_free(asl_file_list_t
*head
)
1829 asl_file_list_t
*next
;
1831 while (head
!= NULL
)
1839 static asl_file_list_t
*
1840 asl_file_list_insert(asl_file_list_t
*list
, asl_file_t
*f
, int32_t dir
)
1842 asl_file_list_t
*a
, *b
, *tmp
;
1844 if (f
== NULL
) return list
;
1846 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1847 if (tmp
== NULL
) return NULL
;
1850 if (list
== NULL
) return tmp
;
1853 if (((dir
< 0) && (f
->cursor_xid
> a
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< a
->file
->cursor_xid
)))
1862 if (((dir
< 0) && (f
->cursor_xid
> b
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< b
->file
->cursor_xid
)))
1878 asl_file_list_add(asl_file_list_t
*list
, asl_file_t
*f
)
1880 asl_file_list_t
*tmp
;
1882 if (f
== NULL
) return list
;
1883 if (f
->version
== 1) return list
;
1885 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1886 if (tmp
== NULL
) return NULL
;
1894 asl_file_list_match_start(asl_file_list_t
*list
, uint64_t start_id
, int32_t direction
)
1898 asl_file_match_token_t
*out
;
1900 if (list
== NULL
) return NULL
;
1902 out
= (asl_file_match_token_t
*)calloc(1, sizeof(asl_file_match_token_t
));
1903 if (out
== NULL
) return NULL
;
1905 for (n
= list
; n
!= NULL
; n
= n
->next
)
1907 /* init file for the search */
1908 status
= asl_file_match_start(n
->file
, start_id
, direction
);
1909 if (status
!= ASL_STATUS_OK
) continue;
1910 if (n
->file
->cursor_xid
== 0) continue;
1912 out
->list
= asl_file_list_insert(out
->list
, n
->file
, direction
);
1915 out
->dir
= direction
;
1920 asl_file_list_match_next(void *token
, aslresponse query
, aslresponse
*res
, uint32_t count
)
1922 uint32_t status
, rescount
;
1925 asl_file_match_token_t
*work
;
1928 if (token
== NULL
) return ASL_STATUS_OK
;
1929 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1931 work
= (asl_file_match_token_t
*)token
;
1936 while ((work
->list
!= NULL
) && ((rescount
< count
) || (count
== 0)))
1939 status
= asl_file_match_next(work
->list
->file
, query
, &m
, &last_id
, work
->dir
);
1942 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
1945 asl_file_list_free(work
->list
);
1947 return ASL_STATUS_NO_MEMORY
;
1950 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1951 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1952 if ((*res
)->msg
== NULL
)
1956 asl_file_list_free(work
->list
);
1958 return ASL_STATUS_NO_MEMORY
;
1961 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
1966 if ((status
!= ASL_STATUS_OK
) || (work
->list
->file
->cursor_xid
== 0))
1968 n
= work
->list
->next
;
1973 if (work
->list
!= NULL
)
1975 n
= work
->list
->next
;
1978 if (((work
->dir
< 0) && (work
->list
->file
->cursor_xid
<= n
->file
->cursor_xid
)) || ((work
->dir
>= 0) && (work
->list
->file
->cursor_xid
> n
->file
->cursor_xid
)))
1981 work
->list
= work
->list
->next
;
1983 work
->list
= asl_file_list_insert(work
->list
, n
->file
, work
->dir
);
1990 return ASL_STATUS_OK
;
1994 asl_file_list_match_end(void *token
)
1996 asl_file_match_token_t
*work
;
1998 if (token
== NULL
) return;
2000 work
= (asl_file_match_token_t
*)token
;
2001 asl_file_list_free(work
->list
);
2008 asl_file_list_match_timeout(asl_file_list_t
*list
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
, uint32_t usec
)
2010 uint32_t status
, rescount
;
2011 asl_file_list_t
*files
, *n
;
2013 struct timeval now
, finish
;
2015 if (list
== NULL
) return ASL_STATUS_INVALID_ARG
;
2016 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
2017 if (last_id
== NULL
) return ASL_STATUS_INVALID_ARG
;
2021 for (n
= list
; n
!= NULL
; n
= n
->next
)
2023 /* init file for the search */
2024 status
= asl_file_match_start(n
->file
, start_id
, direction
);
2025 if (status
!= ASL_STATUS_OK
) continue;
2026 if (n
->file
->cursor_xid
== 0) continue;
2028 files
= asl_file_list_insert(files
, n
->file
, direction
);
2033 asl_file_list_free(files
);
2034 return ASL_STATUS_OK
;
2037 /* start the timer if a timeout was specified */
2038 memset(&finish
, 0, sizeof(struct timeval
));
2041 if (gettimeofday(&finish
, NULL
) == 0)
2043 finish
.tv_sec
+= (usec
/ MILLION
);
2044 finish
.tv_usec
+= (usec
% MILLION
);
2045 if (finish
.tv_usec
> MILLION
)
2047 finish
.tv_usec
-= MILLION
;
2053 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
2054 memset(&finish
, 0, sizeof(struct timeval
));
2059 while ((files
!= NULL
) && ((rescount
< count
) || (count
== 0)))
2062 status
= asl_file_match_next(files
->file
, query
, &m
, last_id
, direction
);
2065 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
2068 asl_file_list_free(files
);
2069 return ASL_STATUS_NO_MEMORY
;
2072 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
2073 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
2074 if ((*res
)->msg
== NULL
)
2078 asl_file_list_free(files
);
2079 return ASL_STATUS_NO_MEMORY
;
2082 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
2087 if (files
->file
->cursor_xid
== 0)
2099 if (((direction
< 0) && (files
->file
->cursor_xid
<= n
->file
->cursor_xid
)) || ((direction
>= 0) && (files
->file
->cursor_xid
> n
->file
->cursor_xid
)))
2102 files
= files
->next
;
2104 files
= asl_file_list_insert(files
, n
->file
, direction
);
2110 /* check the timer */
2111 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
2113 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
2117 asl_file_list_free(files
);
2118 return ASL_STATUS_OK
;
2122 asl_file_list_match(asl_file_list_t
*list
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
2124 return asl_file_list_match_timeout(list
, query
, res
, last_id
, start_id
, count
, direction
, 0);