2 * Copyright (c) 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 2007 Apple Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
32 #include <sys/errno.h>
37 #include <asl_private.h>
38 #include <asl_legacy1.h>
40 extern time_t asl_parse_time(const char *str
);
41 extern int asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
);
43 #define forever for(;;)
44 #define MILLION 1000000
47 * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t)
48 * type and level are both 16 bit fields so that alignment isn't a pain.
50 #define RECORD_COMMON_LEN 6
51 #define RECORD_TYPE_LEN 2
52 #define BUFFER_OFFSET_KVCOUNT 56
54 #define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t)))
82 asl_file_list_t
*list
;
84 } asl_file_match_token_t
;
96 _asl_put_16(uint16_t i
, char *h
)
114 _asl_put_32(uint32_t i
, char *h
)
128 return asl_core_ntohq(x
);
132 _asl_put_64(uint64_t i
, char *h
)
136 x
= asl_core_htonq(i
);
141 asl_file_read_uint32(asl_file_t
*s
, off_t off
, uint32_t *out
)
143 uint32_t status
, val
;
145 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
146 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
147 if ((off
+ sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
149 status
= fseeko(s
->store
, off
, SEEK_SET
);
150 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
154 status
= fread(&val
, sizeof(uint32_t), 1, s
->store
);
155 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
157 if (out
!= NULL
) *out
= ntohl(val
);
158 return ASL_STATUS_OK
;
162 asl_file_read_uint64(asl_file_t
*s
, off_t off
, uint64_t *out
)
167 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
168 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
169 if ((off
+ sizeof(uint64_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
171 status
= fseeko(s
->store
, off
, SEEK_SET
);
172 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
176 status
= fread(&val
, sizeof(uint64_t), 1, s
->store
);
177 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
179 if (out
!= NULL
) *out
= asl_core_ntohq(val
);
180 return ASL_STATUS_OK
;
184 asl_file_close(asl_file_t
*s
)
188 if (s
== NULL
) return ASL_STATUS_OK
;
192 return asl_legacy1_close((asl_legacy1_t
*)s
->legacy
);
195 while (s
->string_list
!= NULL
)
197 x
= s
->string_list
->next
;
198 free(s
->string_list
);
202 if (s
->store
!= NULL
) fclose(s
->store
);
203 if (s
->scratch
!= NULL
) free(s
->scratch
);
205 memset(s
, 0, sizeof(asl_file_t
));
208 return ASL_STATUS_OK
;
212 asl_file_open_write(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, asl_file_t
**s
)
217 char buf
[DB_HEADER_LEN
];
219 uint32_t aslstatus
, vers
;
221 memset(&sb
, 0, sizeof(struct stat
));
223 status
= stat(path
, &sb
);
226 /* XXX Check that mode, uid, and gid are correct */
227 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
228 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
230 out
->store
= fopen(path
, "r+");
231 if (out
->store
== NULL
)
234 return ASL_STATUS_FAILED
;
237 i
= fread(buf
, DB_HEADER_LEN
, 1, out
->store
);
241 return ASL_STATUS_READ_FAILED
;
245 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
248 return ASL_STATUS_INVALID_STORE
;
252 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
253 if (vers
!= DB_VERSION
)
256 return ASL_STATUS_INVALID_STORE
;
259 out
->dob
= _asl_get_64(buf
+ DB_HEADER_TIME_OFFSET
);
260 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
261 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
262 out
->file_size
= (size_t)sb
.st_size
;
264 /* detect bogus last pointer */
265 if (out
->last
>= out
->file_size
) out
->last
= 0;
267 aslstatus
= asl_file_read_set_position(out
, ASL_FILE_POSITION_LAST
);
268 if (aslstatus
!= ASL_STATUS_OK
)
274 out
->prev
= out
->cursor
;
275 status
= fseeko(out
->store
, 0, SEEK_END
);
279 return ASL_STATUS_READ_FAILED
;
282 out
->file_size
= (size_t)ftello(out
->store
);
284 /* scratch buffer for file writes (we test for NULL before using it) */
285 out
->scratch
= malloc(SCRATCH_BUFFER_SIZE
);
289 return ASL_STATUS_OK
;
292 if (errno
!= ENOENT
) return ASL_STATUS_FAILED
;
294 fd
= open(path
, O_RDWR
| O_CREAT
| O_EXCL
, mode
);
295 if (fd
< 0) return ASL_STATUS_FAILED
;
297 status
= fchown(fd
, uid
, gid
);
302 return ASL_STATUS_FAILED
;
305 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
306 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
308 out
->store
= fdopen(fd
, "w+");
309 if (out
->store
== NULL
)
312 return ASL_STATUS_FAILED
;
315 memset(buf
, 0, sizeof(buf
));
316 memcpy(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
);
318 _asl_put_32(DB_VERSION
, buf
+ DB_HEADER_VERS_OFFSET
);
322 _asl_put_64(out
->dob
, buf
+ DB_HEADER_TIME_OFFSET
);
324 _asl_put_32(CACHE_SIZE
, buf
+ DB_HEADER_CSIZE_OFFSET
);
326 status
= fwrite(buf
, sizeof(buf
), 1, out
->store
);
332 return ASL_STATUS_FAILED
;
335 out
->file_size
= sizeof(buf
);
339 return ASL_STATUS_OK
;
343 asl_file_compact(asl_file_t
*s
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
351 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
352 if (path
== NULL
) return ASL_STATUS_INVALID_ARG
;
354 if (s
->version
== 1) return ASL_STATUS_FAILED
;
356 memset(&sb
, 0, sizeof(struct stat
));
358 if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
;
359 if (errno
!= ENOENT
) return ASL_STATUS_FAILED
;
361 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
362 if (status
!= ASL_STATUS_OK
) return status
;
365 status
= asl_file_open_write(path
, mode
, uid
, gid
, &new);
366 if (status
!= ASL_STATUS_OK
) return status
;
367 new->flags
= ASL_FILE_FLAG_UNLIMITED_CACHE
| ASL_FILE_FLAG_PRESERVE_MSG_ID
;
369 while ((status
== ASL_STATUS_OK
) && (s
->cursor
!= 0))
372 status
= asl_file_fetch_next(s
, &m
);
373 if (status
!= ASL_STATUS_OK
) break;
376 status
= asl_file_save(new, m
, &xid
);
385 asl_file_string_encode(asl_file_t
*s
, const char *str
, uint64_t *out
)
387 uint32_t i
, hash
, len
, x32
;
388 file_string_t
*sp
, *sx
, *sl
;
395 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
396 if (str
== NULL
) return ASL_STATUS_INVALID_ARG
;
410 memcpy(p
+ 1, str
, len
);
411 *out
= asl_core_ntohq(x64
);
412 return ASL_STATUS_OK
;
415 /* check the cache */
416 hash
= asl_core_string_hash(str
, len
);
419 for (sx
= s
->string_list
; sx
!= NULL
; sx
= sx
->next
)
421 if ((hash
== sx
->hash
) && (!strcmp(str
, sx
->str
)))
423 /* Move this string to the head of the list */
433 return ASL_STATUS_OK
;
439 off
= ftello(s
->store
);
442 type
= htons(ASL_FILE_TYPE_STR
);
443 i
= fwrite(&type
, sizeof(uint16_t), 1, s
->store
);
444 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
446 /* Length (includes trailing nul) */
447 x32
= htonl(len
+ 1);
448 i
= fwrite(&x32
, sizeof(uint32_t), 1, s
->store
);
449 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
451 /* String data (nul terminated) */
452 i
= fwrite(str
, len
+ 1, 1, s
->store
);
453 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
455 /* create file_string_t and insert into the cache */
456 sx
= (file_string_t
*)calloc(1, offsetof(file_string_t
, str
) + len
+ 1);
457 if (sx
== NULL
) return ASL_STATUS_NO_MEMORY
;
461 sx
->next
= s
->string_list
;
462 memcpy(sx
->str
, str
, len
);
466 if (((s
->flags
& ASL_FILE_FLAG_UNLIMITED_CACHE
) == 0) && (s
->string_count
== CACHE_SIZE
))
468 /* drop last (lru) string from cache */
472 /* NB CACHE_SIZE must be > 1 */
473 while (sx
->next
!= NULL
)
488 return ASL_STATUS_OK
;
492 * Encode an aslmsg as a record structure.
493 * Creates and caches strings.
496 asl_file_save(asl_file_t
*s
, aslmsg msg
, uint64_t *mid
)
499 uint32_t len
, i
, status
;
505 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
506 if (msg
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
508 if (s
->flags
& ASL_FILE_FLAG_READ_ONLY
) return ASL_STATUS_READ_ONLY
;
510 memset(&r
, 0, sizeof(file_record_t
));
513 r
.level
= ASL_LEVEL_DEBUG
;
524 for (i
= 0; i
< msg
->count
; i
++)
526 if (msg
->key
[i
] == NULL
)
530 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME
))
532 if (msg
->val
[i
] != NULL
) r
.time
= asl_parse_time(msg
->val
[i
]);
534 else if (!strcmp(msg
->key
[i
], ASL_KEY_TIME_NSEC
))
536 if (msg
->val
[i
] != NULL
) r
.nano
= atoi(msg
->val
[i
]);
538 else if (!strcmp(msg
->key
[i
], ASL_KEY_HOST
))
540 if (msg
->val
[i
] != NULL
)
542 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.host
));
543 if (status
!= ASL_STATUS_OK
)
545 if (kvlist
!= NULL
) free(kvlist
);
550 else if (!strcmp(msg
->key
[i
], ASL_KEY_SENDER
))
552 if (msg
->val
[i
] != NULL
)
554 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.sender
));
555 if (status
!= ASL_STATUS_OK
)
557 if (kvlist
!= NULL
) free(kvlist
);
562 else if (!strcmp(msg
->key
[i
], ASL_KEY_PID
))
564 if (msg
->val
[i
] != NULL
) r
.pid
= atoi(msg
->val
[i
]);
566 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PID
))
568 if (msg
->val
[i
] != NULL
) r
.refpid
= atoi(msg
->val
[i
]);
570 else if (!strcmp(msg
->key
[i
], ASL_KEY_UID
))
572 if (msg
->val
[i
] != NULL
) r
.uid
= atoi(msg
->val
[i
]);
574 else if (!strcmp(msg
->key
[i
], ASL_KEY_GID
))
576 if (msg
->val
[i
] != NULL
) r
.gid
= atoi(msg
->val
[i
]);
578 else if (!strcmp(msg
->key
[i
], ASL_KEY_LEVEL
))
580 if (msg
->val
[i
] != NULL
) r
.level
= atoi(msg
->val
[i
]);
582 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG
))
584 if (msg
->val
[i
] != NULL
)
586 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.message
));
587 if (status
!= ASL_STATUS_OK
)
589 if (kvlist
!= NULL
) free(kvlist
);
594 else if (!strcmp(msg
->key
[i
], ASL_KEY_FACILITY
))
596 if (msg
->val
[i
] != NULL
)
598 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.facility
));
599 if (status
!= ASL_STATUS_OK
)
601 if (kvlist
!= NULL
) free(kvlist
);
606 else if (!strcmp(msg
->key
[i
], ASL_KEY_REF_PROC
))
608 if (msg
->val
[i
] != NULL
)
610 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.refproc
));
611 if (status
!= ASL_STATUS_OK
)
613 if (kvlist
!= NULL
) free(kvlist
);
618 else if (!strcmp(msg
->key
[i
], ASL_KEY_SESSION
))
620 if (msg
->val
[i
] != NULL
)
622 status
= asl_file_string_encode(s
, msg
->val
[i
], &(r
.session
));
623 if (status
!= ASL_STATUS_OK
)
625 if (kvlist
!= NULL
) free(kvlist
);
630 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_UID
))
632 if (((r
.flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (msg
->val
[i
] != NULL
))
634 r
.ruid
= atoi(msg
->val
[i
]);
635 r
.flags
|= ASL_MSG_FLAG_READ_UID_SET
;
638 else if (!strcmp(msg
->key
[i
], ASL_KEY_READ_GID
))
640 if (((r
.flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (msg
->val
[i
] != NULL
))
642 r
.rgid
= atoi(msg
->val
[i
]);
643 r
.flags
|= ASL_MSG_FLAG_READ_GID_SET
;
646 else if (!strcmp(msg
->key
[i
], ASL_KEY_MSG_ID
))
648 if (s
->flags
& ASL_FILE_FLAG_PRESERVE_MSG_ID
) *mid
= atoll(msg
->val
[i
]);
650 else if (!strcmp(msg
->key
[i
], ASL_KEY_OPTION
))
652 /* ignore - we don't save ASLOption */
656 status
= asl_file_string_encode(s
, msg
->key
[i
], &k
);
657 if (status
!= ASL_STATUS_OK
)
659 if (kvlist
!= NULL
) free(kvlist
);
664 if (msg
->val
[i
] != NULL
)
666 status
= asl_file_string_encode(s
, msg
->val
[i
], &v
);
667 if (status
!= ASL_STATUS_OK
)
669 if (kvlist
!= NULL
) free(kvlist
);
676 kvlist
= (uint64_t *)calloc(2, sizeof(uint64_t));
680 kvlist
= (uint64_t *)reallocf(kvlist
, (r
.kvcount
+ 2) * sizeof(uint64_t));
685 return ASL_STATUS_NO_MEMORY
;
688 kvlist
[r
.kvcount
++] = k
;
689 kvlist
[r
.kvcount
++] = v
;
693 len
= MSG_RECORD_FIXED_LENGTH
+ (r
.kvcount
* sizeof(uint64_t));
696 /* use the scratch buffer if it exists and is large enough */
697 if ((s
->scratch
!= NULL
) && (len
<= SCRATCH_BUFFER_SIZE
))
699 memset(s
->scratch
, 0, SCRATCH_BUFFER_SIZE
);
704 buf
= calloc(1, len
);
707 if (buf
== NULL
) return ASL_STATUS_NO_MEMORY
;
715 r
.mid
= asl_core_new_msg_id(0);
722 _asl_put_16(ASL_FILE_TYPE_MSG
, p
);
723 p
+= sizeof(uint16_t);
725 /* Length of message (excludes type and length fields) */
726 _asl_put_32(len
- RECORD_COMMON_LEN
, p
);
727 p
+= sizeof(uint32_t);
729 /* Message data... */
731 _asl_put_64(r
.next
, p
);
732 p
+= sizeof(uint64_t);
734 _asl_put_64(r
.mid
, p
);
735 p
+= sizeof(uint64_t);
737 _asl_put_64(r
.time
, p
);
738 p
+= sizeof(uint64_t);
740 _asl_put_32(r
.nano
, p
);
741 p
+= sizeof(uint32_t);
743 _asl_put_16(r
.level
, p
);
744 p
+= sizeof(uint16_t);
746 _asl_put_16(r
.flags
, p
);
747 p
+= sizeof(uint16_t);
749 _asl_put_32(r
.pid
, p
);
750 p
+= sizeof(uint32_t);
752 _asl_put_32(r
.uid
, p
);
753 p
+= sizeof(uint32_t);
755 _asl_put_32(r
.gid
, p
);
756 p
+= sizeof(uint32_t);
758 _asl_put_32(r
.ruid
, p
);
759 p
+= sizeof(uint32_t);
761 _asl_put_32(r
.rgid
, p
);
762 p
+= sizeof(uint32_t);
764 _asl_put_32(r
.refpid
, p
);
765 p
+= sizeof(uint32_t);
767 _asl_put_32(r
.kvcount
, p
);
768 p
+= sizeof(uint32_t);
770 _asl_put_64(r
.host
, p
);
771 p
+= sizeof(uint64_t);
773 _asl_put_64(r
.sender
, p
);
774 p
+= sizeof(uint64_t);
776 _asl_put_64(r
.facility
, p
);
777 p
+= sizeof(uint64_t);
779 _asl_put_64(r
.message
, p
);
780 p
+= sizeof(uint64_t);
782 _asl_put_64(r
.refproc
, p
);
783 p
+= sizeof(uint64_t);
785 _asl_put_64(r
.session
, p
);
786 p
+= sizeof(uint64_t);
788 for (i
= 0; i
< r
.kvcount
; i
++)
790 _asl_put_64(kvlist
[i
], p
);
791 p
+= sizeof(uint64_t);
794 _asl_put_64(r
.prev
, p
);
795 p
+= sizeof(uint64_t);
800 /* write record at end of file */
801 status
= fseeko(s
->store
, 0, SEEK_END
);
802 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
804 s
->last
= (uint64_t)ftello(s
->store
);
806 v
= asl_core_htonq(s
->last
);
808 status
= fwrite(buf
, len
, 1, s
->store
);
811 /* free the buffer if it was allocated here */
812 if (buf
!= s
->scratch
) free(buf
);
814 /* seek to "next" field of previous record, write last offset */
815 off
= s
->prev
+ RECORD_COMMON_LEN
;
816 if (s
->prev
== 0) off
= DB_HEADER_FIRST_OFFSET
;
818 status
= fseeko(s
->store
, off
, SEEK_SET
);
819 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
821 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
822 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
824 /* seek to DB_HEADER_LAST_OFFSET, write last record offset */
825 off
= DB_HEADER_LAST_OFFSET
;
827 status
= fseeko(s
->store
, off
, SEEK_SET
);
828 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
830 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
831 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
833 /* return to the end of the store (this is expected by other routines) */
834 status
= fseeko(s
->store
, 0, SEEK_END
);
835 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
837 s
->file_size
= (size_t)ftello(s
->store
);
841 return ASL_STATUS_OK
;
845 asl_file_fetch_object(asl_file_t
*s
, uint64_t where
, char **out
, uint32_t *outlen
)
859 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
860 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
861 if (where
== 0) return ASL_STATUS_INVALID_ARG
;
864 x64
= asl_core_htonq(where
);
865 memcpy(&inls
, &x64
, 1);
870 if (inls
> 7) return ASL_STATUS_INVALID_STORE
;
872 p
= 1 + (char *)&x64
;
873 memset(ils
, 0, sizeof(ils
));
874 memcpy(ils
, p
, inls
);
876 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
879 return ASL_STATUS_OK
;
883 if ((off
+ sizeof(uint16_t) + sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
885 status
= fseeko(s
->store
, off
, SEEK_SET
);
886 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
889 status
= fread(&type
, sizeof(uint16_t), 1, s
->store
);
890 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
891 off
+= sizeof(uint16_t);
895 status
= fread(&len
, sizeof(uint32_t), 1, s
->store
);
896 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
897 off
+= sizeof(uint32_t);
900 if ((off
+ len
) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
902 *out
= calloc(1, len
);
903 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
905 status
= fread(*out
, len
, 1, s
->store
);
909 return ASL_STATUS_READ_FAILED
;
913 return ASL_STATUS_OK
;
917 asl_file_fetch_helper_16(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
922 out
= _asl_get_16(*p
);
923 *p
+= sizeof(uint16_t);
925 if ((m
== NULL
) || (key
== NULL
)) return out
;
927 snprintf(str
, sizeof(str
), "%hu", out
);
928 asl_set(m
, key
, str
);
934 asl_file_fetch_helper_32(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, int ignore
, uint32_t ignoreval
)
939 out
= _asl_get_32(*p
);
940 *p
+= sizeof(uint32_t);
942 if ((m
== NULL
) || (key
== NULL
)) return out
;
945 if ((ignore
!= 0) && (out
== ignoreval
)) doit
= 0;
948 snprintf(str
, sizeof(str
), "%u", out
);
949 asl_set(m
, key
, str
);
956 asl_file_fetch_helper_64(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
961 out
= _asl_get_64(*p
);
962 *p
+= sizeof(uint64_t);
964 if ((m
== NULL
) || (key
== NULL
)) return out
;
966 snprintf(str
, sizeof(str
), "%llu", out
);
967 asl_set(m
, key
, str
);
973 asl_file_fetch_helper_str(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, uint32_t *err
)
977 uint32_t status
, len
;
979 out
= _asl_get_64(*p
);
980 *p
+= sizeof(uint64_t);
984 status
= ASL_STATUS_OK
;
985 if (out
!= 0) status
= asl_file_fetch_object(s
, out
, &val
, &len
);
987 if (err
!= NULL
) *err
= status
;
988 if ((status
== ASL_STATUS_OK
) && (val
!= NULL
))
990 asl_set(m
, key
, val
);
998 asl_file_fetch_pos(asl_file_t
*s
, uint64_t where
, int dir
, aslmsg
*msg
)
1000 char *buf
, *p
, *k
, *v
;
1002 uint32_t i
, status
, len
, buflen
, kvn
;
1007 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1008 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1009 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1013 status
= asl_file_fetch_object(s
, where
, &buf
, &buflen
);
1014 if ((status
!= ASL_STATUS_OK
) || (buf
== NULL
))
1021 /* check buffer size */
1022 kvn
= _asl_get_32(buf
+ BUFFER_OFFSET_KVCOUNT
);
1023 if (buflen
< (MSG_RECORD_FIXED_LENGTH
- RECORD_COMMON_LEN
+ (kvn
* sizeof(uint64_t))))
1028 return ASL_STATUS_READ_FAILED
;
1031 out
= asl_new(ASL_TYPE_MSG
);
1032 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1034 memset(&r
, 0, sizeof(file_record_t
));
1037 r
.next
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
);
1038 r
.mid
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_MSG_ID
);
1039 r
.time
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_TIME
);
1040 r
.nano
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_TIME_NSEC
, 0, 0);
1041 r
.level
= asl_file_fetch_helper_16(s
, &p
, out
, ASL_KEY_LEVEL
);
1042 r
.flags
= asl_file_fetch_helper_16(s
, &p
, NULL
, NULL
);
1043 r
.pid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_PID
, 0, 0);
1044 r
.uid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_UID
, 1, (uint32_t)-1);
1045 r
.gid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_GID
, 1, (uint32_t)-1);
1046 r
.ruid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_UID
, 1, (uint32_t)-1);
1047 r
.rgid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_GID
, 1, (uint32_t)-1);
1048 r
.refpid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_REF_PID
, 1, 0);
1049 r
.kvcount
= asl_file_fetch_helper_32(s
, &p
, NULL
, NULL
, 0, 0);
1051 status
= ASL_STATUS_OK
;
1052 r
.host
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_HOST
, &status
); /* 68 */
1053 if (status
== ASL_STATUS_OK
) r
.sender
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SENDER
, &status
); /* 76 */
1054 if (status
== ASL_STATUS_OK
) r
.facility
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_FACILITY
, &status
); /* 84 */
1055 if (status
== ASL_STATUS_OK
) r
.message
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_MSG
, &status
); /* 92 */
1056 if (status
== ASL_STATUS_OK
) r
.refproc
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_REF_PROC
, &status
); /* 100 */
1057 if (status
== ASL_STATUS_OK
) r
.session
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SESSION
, &status
); /* 108 */
1059 if (status
!= ASL_STATUS_OK
)
1068 kvn
= r
.kvcount
/ 2;
1070 for (i
= 0; i
< kvn
; i
++)
1072 kv
= _asl_get_64(p
);
1073 p
+= sizeof(uint64_t);
1076 status
= asl_file_fetch_object(s
, kv
, &k
, &len
);
1077 if (status
!= ASL_STATUS_OK
)
1086 kv
= _asl_get_64(p
);
1087 p
+= sizeof(uint64_t);
1093 status
= asl_file_fetch_object(s
, kv
, &v
, &len
);
1094 if (status
!= ASL_STATUS_OK
)
1104 if ((status
== ASL_STATUS_OK
) && (k
!= NULL
))
1107 if (v
!= NULL
) free(v
);
1112 r
.prev
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
); /* 116 */
1116 if (dir
>= 0) s
->cursor
= r
.next
;
1117 else s
->cursor
= r
.prev
;
1123 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1124 if (off
> s
->file_size
)
1130 * Next record offset is past the end of the file.
1131 * This is an error, but we allow it to fail quietly
1132 * so that the current record fetch succeeds.
1134 return ASL_STATUS_OK
;
1137 status
= fseeko(s
->store
, off
, SEEK_SET
);
1143 return ASL_STATUS_READ_FAILED
;
1146 status
= fread(&x64
, sizeof(uint64_t), 1, s
->store
);
1152 return ASL_STATUS_READ_FAILED
;
1155 s
->cursor_xid
= asl_core_ntohq(x64
);
1159 return ASL_STATUS_OK
;
1163 asl_file_open_read(const char *path
, asl_file_t
**s
)
1168 uint32_t status
, vers
;
1169 char buf
[DB_HEADER_LEN
];
1171 asl_legacy1_t
*legacy
;
1174 memset(&sb
, 0, sizeof(struct stat
));
1175 if (stat(path
, &sb
) != 0) return ASL_STATUS_FAILED
;
1177 f
= fopen(path
, "r");
1180 if (errno
== EACCES
) return ASL_STATUS_ACCESS_DENIED
;
1181 return ASL_STATUS_FAILED
;
1184 i
= fread(buf
, DB_HEADER_LEN
, 1, f
);
1188 return ASL_STATUS_INVALID_STORE
;
1191 /* validate header */
1192 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
1195 return ASL_STATUS_INVALID_STORE
;
1200 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
1201 if (vers
== DB_VERSION_LEGACY_1
)
1204 status
= asl_legacy1_open(path
, &legacy
);
1205 if (status
!= ASL_STATUS_OK
) return status
;
1208 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
1212 return ASL_STATUS_NO_MEMORY
;
1215 out
->flags
= ASL_FILE_FLAG_READ_ONLY
;
1216 out
->version
= vers
;
1220 out
->flags
|= ASL_FILE_FLAG_LEGACY_STORE
;
1221 out
->legacy
= (void *)legacy
;
1224 return ASL_STATUS_OK
;
1227 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
1228 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
1229 out
->file_size
= (size_t)sb
.st_size
;
1231 /* detect bogus last pointer */
1232 if (out
->last
>= out
->file_size
) out
->last
= 0;
1236 out
->cursor
= out
->first
;
1237 if (out
->cursor
!= 0)
1239 off
= out
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1240 status
= asl_file_read_uint64(out
, off
, &(out
->cursor_xid
));
1241 if (status
!= ASL_STATUS_OK
)
1249 return ASL_STATUS_OK
;
1253 asl_file_read_set_position_first(asl_file_t
*s
)
1258 s
->cursor
= s
->first
;
1261 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1263 /* read ID of the first record */
1264 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1265 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1270 asl_file_read_set_position_last(asl_file_t
*s
)
1277 * If the file has the offset of the last record, we just go there.
1278 * The last record offset was added to improve performance, so it may
1279 * or may not be there. If we don't have the last record offset, we
1280 * just iterate down the record links to find the last one.
1282 * Note that s->last may be zero if the file is empty.
1287 s
->cursor
= s
->last
;
1288 off
= s
->last
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1290 /* read ID of the last record */
1291 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1295 /* start at the first record and iterate */
1296 s
->cursor
= s
->first
;
1301 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1304 /* read next offset */
1305 status
= asl_file_read_uint64(s
, off
, &next
);
1306 if (status
!= ASL_STATUS_OK
) return status
;
1308 /* detect bogus next pointer */
1309 if (next
>= s
->file_size
) next
= 0;
1313 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1315 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1316 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1317 return ASL_STATUS_OK
;
1325 asl_file_read_set_position(asl_file_t
*s
, uint32_t pos
)
1327 uint32_t len
, status
;
1330 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1331 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1333 if (pos
== ASL_FILE_POSITION_FIRST
) return asl_file_read_set_position_first(s
);
1334 if (pos
== ASL_FILE_POSITION_LAST
) return asl_file_read_set_position_last(s
);
1338 if (pos
== ASL_FILE_POSITION_PREVIOUS
)
1340 if (s
->cursor
== s
->first
) return ASL_STATUS_NO_RECORDS
;
1341 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1343 off
= s
->cursor
+ RECORD_TYPE_LEN
;
1344 status
= asl_file_read_uint32(s
, off
, &len
);
1345 if (status
!= ASL_STATUS_OK
) return status
;
1347 /* set offset to read the "previous" field at the end of the record */
1348 off
= s
->cursor
+ RECORD_COMMON_LEN
+ len
- sizeof(uint64_t);
1350 else if (pos
== ASL_FILE_POSITION_NEXT
)
1352 if (s
->cursor
== s
->last
) return ASL_STATUS_NO_RECORDS
;
1353 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1355 /* set offset to read the "next" field in the current record */
1356 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1358 else return ASL_STATUS_INVALID_ARG
;
1363 * read offset of next / previous
1365 status
= asl_file_read_uint64(s
, off
, &(s
->cursor
));
1366 if (status
!= ASL_STATUS_OK
) return ASL_STATUS_READ_FAILED
;
1368 /* detect bogus next pointer */
1369 if (s
->cursor
>= s
->file_size
) s
->cursor
= 0;
1371 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1373 /* read ID of the record */
1374 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1375 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1380 asl_file_fetch_next(asl_file_t
*s
, aslmsg
*msg
)
1382 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1383 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1385 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1389 asl_file_fetch_previous(asl_file_t
*s
, aslmsg
*msg
)
1391 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1392 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1394 return asl_file_fetch_pos(s
, s
->cursor
, -1, msg
);
1398 asl_file_fetch(asl_file_t
*s
, uint64_t mid
, aslmsg
*msg
)
1402 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1403 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1404 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1406 if (s
->version
== 1)
1408 return asl_legacy1_fetch((asl_legacy1_t
*)s
->legacy
, mid
, msg
);
1411 if (s
->cursor_xid
== 0)
1413 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1414 if (status
!= ASL_STATUS_OK
) return status
;
1415 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1418 while (s
->cursor_xid
< mid
)
1420 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_NEXT
);
1421 if (status
!= ASL_STATUS_OK
) return status
;
1422 if (s
->cursor_xid
> mid
) return ASL_STATUS_INVALID_ID
;
1423 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1426 while (s
->cursor_xid
> mid
)
1428 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_PREVIOUS
);
1429 if (status
!= ASL_STATUS_OK
) return status
;
1430 if (s
->cursor_xid
< mid
) return ASL_STATUS_INVALID_ID
;
1431 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1434 if (s
->cursor_xid
!= mid
) return ASL_STATUS_INVALID_ID
;
1436 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1440 asl_file_cursor(asl_file_t
*s
)
1442 if (s
== NULL
) return 0;
1443 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return 0;
1444 if (s
->version
== 1) return 0;
1446 return s
->cursor_xid
;
1450 asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
)
1454 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1455 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1456 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1458 d
= ASL_FILE_POSITION_NEXT
;
1459 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1462 * find starting point
1464 status
= ASL_STATUS_OK
;
1465 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1466 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1467 if (status
!= ASL_STATUS_OK
) return status
;
1469 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1471 status
= asl_file_read_set_position(s
, d
);
1478 asl_file_match_next(asl_file_t
*s
, aslresponse query
, asl_msg_t
**msg
, uint64_t *last_id
, int32_t direction
)
1480 uint32_t status
, d
, i
, do_match
, did_match
;
1483 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1484 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1485 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1486 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1487 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1492 d
= ASL_FILE_POSITION_NEXT
;
1493 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1495 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1499 *last_id
= s
->cursor_xid
;
1501 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1502 if (status
== ASL_STATUS_ACCESS_DENIED
) return ASL_STATUS_MATCH_FAILED
;
1503 if ((status
== ASL_STATUS_INVALID_ARG
) && (s
->cursor
== 0)) return ASL_STATUS_NO_RECORDS
;
1504 if (status
!= ASL_STATUS_OK
) return status
;
1512 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1514 did_match
= asl_msg_cmp(query
->msg
[i
], m
);
1521 return ASL_STATUS_OK
;
1525 return ASL_STATUS_MATCH_FAILED
;
1529 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
)
1531 uint32_t status
, d
, i
, do_match
, did_match
, rescount
;
1534 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1535 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1536 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1538 if (s
->version
== 1)
1540 return asl_legacy1_match((asl_legacy1_t
*)s
->legacy
, query
, res
, last_id
, start_id
, count
, direction
);
1546 d
= ASL_FILE_POSITION_NEXT
;
1547 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1549 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1552 * find starting point
1554 status
= ASL_STATUS_OK
;
1555 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1556 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1557 if (status
!= ASL_STATUS_OK
) return status
;
1559 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1561 status
= asl_file_read_set_position(s
, d
);
1565 * loop through records
1570 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1571 if (status
== ASL_STATUS_ACCESS_DENIED
) continue;
1572 if (status
!= ASL_STATUS_OK
) break;
1574 *last_id
= s
->cursor_xid
;
1582 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1584 did_match
= asl_msg_cmp(query
->msg
[i
], m
);
1590 /* append m to res */
1593 *res
= (aslresponse
)calloc(1, sizeof(aslresponse
));
1594 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1595 (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1596 if ((*res
)->msg
== NULL
)
1599 return ASL_STATUS_NO_MEMORY
;
1604 (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(asl_msg_t
*));
1605 if ((*res
)->msg
== NULL
)
1608 return ASL_STATUS_NO_MEMORY
;
1612 (*res
)->msg
[(*res
)->count
] = m
;
1616 if ((count
!= 0) && (rescount
>= count
)) break;
1625 return ASL_STATUS_OK
;
1629 asl_file_size(asl_file_t
*s
)
1631 if (s
== NULL
) return 0;
1632 return s
->file_size
;
1636 asl_file_ctime(asl_file_t
*s
)
1638 if (s
== NULL
) return 0;
1643 asl_file_list_close(asl_file_list_t
*head
)
1645 asl_file_list_t
*next
;
1647 while (head
!= NULL
)
1650 asl_file_close(head
->file
);
1657 asl_file_list_free(asl_file_list_t
*head
)
1659 asl_file_list_t
*next
;
1661 while (head
!= NULL
)
1670 asl_file_list_insert(asl_file_list_t
*list
, asl_file_t
*f
, int32_t dir
)
1672 asl_file_list_t
*a
, *b
, *tmp
;
1674 if (f
== NULL
) return list
;
1676 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1677 if (tmp
== NULL
) return NULL
;
1680 if (list
== NULL
) return tmp
;
1683 if (((dir
< 0) && (f
->cursor_xid
> a
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< a
->file
->cursor_xid
)))
1692 if (((dir
< 0) && (f
->cursor_xid
> b
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< b
->file
->cursor_xid
)))
1708 asl_file_list_add(asl_file_list_t
*list
, asl_file_t
*f
)
1710 asl_file_list_t
*tmp
;
1712 if (f
== NULL
) return list
;
1713 if (f
->version
== 1) return list
;
1715 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1716 if (tmp
== NULL
) return NULL
;
1724 asl_file_list_match_start(asl_file_list_t
*list
, uint64_t start_id
, int32_t direction
)
1728 asl_file_match_token_t
*out
;
1730 if (list
== NULL
) return NULL
;
1732 out
= (asl_file_match_token_t
*)calloc(1, sizeof(asl_file_match_token_t
));
1733 if (out
== NULL
) return NULL
;
1735 for (n
= list
; n
!= NULL
; n
= n
->next
)
1737 /* init file for the search */
1738 status
= asl_file_match_start(n
->file
, start_id
, direction
);
1739 if (status
!= ASL_STATUS_OK
) continue;
1740 if (n
->file
->cursor_xid
== 0) continue;
1742 out
->list
= asl_file_list_insert(out
->list
, n
->file
, direction
);
1745 out
->dir
= direction
;
1750 asl_file_list_match_next(void *token
, aslresponse query
, aslresponse
*res
, uint32_t count
)
1752 uint32_t status
, rescount
;
1755 asl_file_match_token_t
*work
;
1758 if (token
== NULL
) return ASL_STATUS_OK
;
1759 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1761 work
= (asl_file_match_token_t
*)token
;
1766 while ((work
->list
!= NULL
) && ((rescount
< count
) || (count
== 0)))
1769 status
= asl_file_match_next(work
->list
->file
, query
, &m
, &last_id
, work
->dir
);
1772 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
1775 asl_file_list_free(work
->list
);
1777 return ASL_STATUS_NO_MEMORY
;
1780 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1781 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(asl_msg_t
*));
1782 if ((*res
)->msg
== NULL
)
1786 asl_file_list_free(work
->list
);
1788 return ASL_STATUS_NO_MEMORY
;
1791 (*res
)->msg
[(*res
)->count
] = m
;
1796 if ((status
!= ASL_STATUS_OK
) || (work
->list
->file
->cursor_xid
== 0))
1798 n
= work
->list
->next
;
1803 if (work
->list
!= NULL
)
1805 n
= work
->list
->next
;
1808 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
)))
1811 work
->list
= work
->list
->next
;
1813 work
->list
= asl_file_list_insert(work
->list
, n
->file
, work
->dir
);
1820 return ASL_STATUS_OK
;
1824 asl_file_list_match_end(void *token
)
1826 asl_file_match_token_t
*work
;
1828 if (token
== NULL
) return;
1830 work
= (asl_file_match_token_t
*)token
;
1831 asl_file_list_free(work
->list
);
1838 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
)
1840 uint32_t status
, rescount
;
1841 asl_file_list_t
*files
, *n
;
1843 struct timeval now
, finish
;
1845 if (list
== NULL
) return ASL_STATUS_INVALID_ARG
;
1846 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1847 if (last_id
== NULL
) return ASL_STATUS_INVALID_ARG
;
1851 for (n
= list
; n
!= NULL
; n
= n
->next
)
1853 /* init file for the search */
1854 status
= asl_file_match_start(n
->file
, start_id
, direction
);
1855 if (status
!= ASL_STATUS_OK
) continue;
1856 if (n
->file
->cursor_xid
== 0) continue;
1858 files
= asl_file_list_insert(files
, n
->file
, direction
);
1863 asl_file_list_free(files
);
1864 return ASL_STATUS_OK
;
1867 /* start the timer if a timeout was specified */
1868 memset(&finish
, 0, sizeof(struct timeval
));
1871 if (gettimeofday(&finish
, NULL
) == 0)
1873 finish
.tv_sec
+= (usec
/ MILLION
);
1874 finish
.tv_usec
+= (usec
% MILLION
);
1875 if (finish
.tv_usec
> MILLION
)
1877 finish
.tv_usec
-= MILLION
;
1883 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
1884 memset(&finish
, 0, sizeof(struct timeval
));
1889 while ((files
!= NULL
) && ((rescount
< count
) || (count
== 0)))
1892 status
= asl_file_match_next(files
->file
, query
, &m
, last_id
, direction
);
1895 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
1898 asl_file_list_free(files
);
1899 return ASL_STATUS_NO_MEMORY
;
1902 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1903 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(asl_msg_t
*));
1904 if ((*res
)->msg
== NULL
)
1908 asl_file_list_free(files
);
1909 return ASL_STATUS_NO_MEMORY
;
1912 (*res
)->msg
[(*res
)->count
] = m
;
1917 if (files
->file
->cursor_xid
== 0)
1929 if (((direction
< 0) && (files
->file
->cursor_xid
<= n
->file
->cursor_xid
)) || ((direction
>= 0) && (files
->file
->cursor_xid
> n
->file
->cursor_xid
)))
1932 files
= files
->next
;
1934 files
= asl_file_list_insert(files
, n
->file
, direction
);
1940 /* check the timer */
1941 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
1943 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
1947 asl_file_list_free(files
);
1948 return ASL_STATUS_OK
;
1952 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
)
1954 return asl_file_list_match_timeout(list
, query
, res
, last_id
, start_id
, count
, direction
, 0);