]> git.saurik.com Git - apple/libc.git/blob - gen/asl_file.c
Libc-594.9.1.tar.gz
[apple/libc.git] / gen / asl_file.c
1 /*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <asl_core.h>
26 #include <asl_file.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <sys/errno.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include <sys/time.h>
37 #include <asl_private.h>
38 #include <asl_legacy1.h>
39
40 extern time_t asl_parse_time(const char *str);
41 extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
42
43 #define forever for(;;)
44 #define MILLION 1000000
45
46 /*
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.
49 */
50 #define RECORD_COMMON_LEN 6
51 #define RECORD_TYPE_LEN 2
52 #define BUFFER_OFFSET_KVCOUNT 56
53
54 #define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t)))
55
56 typedef struct
57 {
58 uint64_t next;
59 uint64_t mid;
60 uint64_t time;
61 uint32_t nano;
62 uint16_t level;
63 uint16_t flags;
64 uint32_t pid;
65 uint32_t uid;
66 uint32_t gid;
67 uint32_t ruid;
68 uint32_t rgid;
69 uint32_t refpid;
70 uint32_t kvcount;
71 uint64_t host;
72 uint64_t sender;
73 uint64_t facility;
74 uint64_t message;
75 uint64_t refproc;
76 uint64_t session;
77 uint64_t prev;
78 } file_record_t;
79
80 typedef struct
81 {
82 asl_file_list_t *list;
83 int dir;
84 } asl_file_match_token_t;
85
86 static uint16_t
87 _asl_get_16(char *h)
88 {
89 uint16_t x;
90
91 memcpy(&x, h, 2);
92 return ntohs(x);
93 }
94
95 static void
96 _asl_put_16(uint16_t i, char *h)
97 {
98 uint16_t x;
99
100 x = htons(i);
101 memcpy(h, &x, 2);
102 }
103
104 static uint32_t
105 _asl_get_32(char *h)
106 {
107 uint32_t x;
108
109 memcpy(&x, h, 4);
110 return ntohl(x);
111 }
112
113 static void
114 _asl_put_32(uint32_t i, char *h)
115 {
116 uint32_t x;
117
118 x = htonl(i);
119 memcpy(h, &x, 4);
120 }
121
122 static uint64_t
123 _asl_get_64(char *h)
124 {
125 uint64_t x;
126
127 memcpy(&x, h, 8);
128 return asl_core_ntohq(x);
129 }
130
131 static void
132 _asl_put_64(uint64_t i, char *h)
133 {
134 uint64_t x;
135
136 x = asl_core_htonq(i);
137 memcpy(h, &x, 8);
138 }
139
140 static uint32_t
141 asl_file_read_uint32(asl_file_t *s, off_t off, uint32_t *out)
142 {
143 uint32_t status, val;
144
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;
148
149 status = fseeko(s->store, off, SEEK_SET);
150 if (status != 0) return ASL_STATUS_READ_FAILED;
151
152 val = 0;
153
154 status = fread(&val, sizeof(uint32_t), 1, s->store);
155 if (status != 1) return ASL_STATUS_READ_FAILED;
156
157 if (out != NULL) *out = ntohl(val);
158 return ASL_STATUS_OK;
159 }
160
161 static uint32_t
162 asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out)
163 {
164 uint32_t status;
165 uint64_t val;
166
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;
170
171 status = fseeko(s->store, off, SEEK_SET);
172 if (status != 0) return ASL_STATUS_READ_FAILED;
173
174 val = 0;
175
176 status = fread(&val, sizeof(uint64_t), 1, s->store);
177 if (status != 1) return ASL_STATUS_READ_FAILED;
178
179 if (out != NULL) *out = asl_core_ntohq(val);
180 return ASL_STATUS_OK;
181 }
182
183 uint32_t
184 asl_file_close(asl_file_t *s)
185 {
186 file_string_t *x;
187
188 if (s == NULL) return ASL_STATUS_OK;
189
190 if (s->version == 1)
191 {
192 return asl_legacy1_close((asl_legacy1_t *)s->legacy);
193 }
194
195 while (s->string_list != NULL)
196 {
197 x = s->string_list->next;
198 free(s->string_list);
199 s->string_list = x;
200 }
201
202 if (s->store != NULL) fclose(s->store);
203 if (s->scratch != NULL) free(s->scratch);
204
205 memset(s, 0, sizeof(asl_file_t));
206 free(s);
207
208 return ASL_STATUS_OK;
209 }
210
211 uint32_t
212 asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_file_t **s)
213 {
214 time_t now;
215 int i, status, fd;
216 struct stat sb;
217 char buf[DB_HEADER_LEN];
218 asl_file_t *out;
219 uint32_t aslstatus, vers;
220
221 memset(&sb, 0, sizeof(struct stat));
222
223 status = stat(path, &sb);
224 if (status == 0)
225 {
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;
229
230 out->store = fopen(path, "r+");
231 if (out->store == NULL)
232 {
233 free(out);
234 return ASL_STATUS_FAILED;
235 }
236
237 i = fread(buf, DB_HEADER_LEN, 1, out->store);
238 if (i < 1)
239 {
240 asl_file_close(out);
241 return ASL_STATUS_READ_FAILED;
242 }
243
244 /* check cookie */
245 if (strncmp(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
246 {
247 asl_file_close(out);
248 return ASL_STATUS_INVALID_STORE;
249 }
250
251 /* check version */
252 vers = _asl_get_32(buf + DB_HEADER_VERS_OFFSET);
253 if (vers != DB_VERSION)
254 {
255 asl_file_close(out);
256 return ASL_STATUS_INVALID_STORE;
257 }
258
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;
263
264 /* detect bogus last pointer */
265 if (out->last >= out->file_size) out->last = 0;
266
267 aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST);
268 if (aslstatus != ASL_STATUS_OK)
269 {
270 asl_file_close(out);
271 return aslstatus;
272 }
273
274 out->prev = out->cursor;
275 status = fseeko(out->store, 0, SEEK_END);
276 if (status != 0)
277 {
278 asl_file_close(out);
279 return ASL_STATUS_READ_FAILED;
280 }
281
282 out->file_size = (size_t)ftello(out->store);
283
284 /* scratch buffer for file writes (we test for NULL before using it) */
285 out->scratch = malloc(SCRATCH_BUFFER_SIZE);
286
287 *s = out;
288
289 return ASL_STATUS_OK;
290 }
291
292 if (errno != ENOENT) return ASL_STATUS_FAILED;
293
294 fd = open(path, O_RDWR | O_CREAT | O_EXCL, mode);
295 if (fd < 0) return ASL_STATUS_FAILED;
296
297 status = fchown(fd, uid, gid);
298 if (status != 0)
299 {
300 close(fd);
301 unlink(path);
302 return ASL_STATUS_FAILED;
303 }
304
305 out = (asl_file_t *)calloc(1, sizeof(asl_file_t));
306 if (out == NULL) return ASL_STATUS_NO_MEMORY;
307
308 out->store = fdopen(fd, "w+");
309 if (out->store == NULL)
310 {
311 free(out);
312 return ASL_STATUS_FAILED;
313 }
314
315 memset(buf, 0, sizeof(buf));
316 memcpy(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN);
317
318 _asl_put_32(DB_VERSION, buf + DB_HEADER_VERS_OFFSET);
319
320 now = time(NULL);
321 out->dob = now;
322 _asl_put_64(out->dob, buf + DB_HEADER_TIME_OFFSET);
323
324 _asl_put_32(CACHE_SIZE, buf + DB_HEADER_CSIZE_OFFSET);
325
326 status = fwrite(buf, sizeof(buf), 1, out->store);
327 if (status != 1)
328 {
329 fclose(out->store);
330 free(out);
331 unlink(path);
332 return ASL_STATUS_FAILED;
333 }
334
335 out->file_size = sizeof(buf);
336
337 *s = out;
338
339 return ASL_STATUS_OK;
340 }
341
342 uint32_t
343 asl_file_compact(asl_file_t *s, const char *path, mode_t mode, uid_t uid, gid_t gid)
344 {
345 asl_file_t *new;
346 struct stat sb;
347 aslmsg m;
348 uint64_t xid;
349 uint32_t status;
350
351 if (s == NULL) return ASL_STATUS_INVALID_STORE;
352 if (path == NULL) return ASL_STATUS_INVALID_ARG;
353
354 if (s->version == 1) return ASL_STATUS_FAILED;
355
356 memset(&sb, 0, sizeof(struct stat));
357
358 if (stat(path, &sb) == 0) return ASL_STATUS_FAILED;
359 if (errno != ENOENT) return ASL_STATUS_FAILED;
360
361 status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST);
362 if (status != ASL_STATUS_OK) return status;
363
364 new = NULL;
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;
368
369 while ((status == ASL_STATUS_OK) && (s->cursor != 0))
370 {
371 m = NULL;
372 status = asl_file_fetch_next(s, &m);
373 if (status != ASL_STATUS_OK) break;
374
375 xid = 0;
376 status = asl_file_save(new, m, &xid);
377 asl_free(m);
378 }
379
380 asl_file_close(new);
381 return status;
382 }
383
384 static uint32_t
385 asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
386 {
387 uint32_t i, hash, len, x32;
388 file_string_t *sp, *sx, *sl;
389 uint64_t x64;
390 uint8_t inls;
391 uint16_t type;
392 off_t off;
393 char *p;
394
395 if (s == NULL) return ASL_STATUS_INVALID_STORE;
396 if (str == NULL) return ASL_STATUS_INVALID_ARG;
397
398 len = strlen(str);
399
400 /* inline strings */
401 if (len < 8)
402 {
403 /* inline string */
404 inls = len;
405 inls |= 0x80;
406
407 x64 = 0;
408 p = (char *)&x64;
409 memcpy(p, &inls, 1);
410 memcpy(p + 1, str, len);
411 *out = asl_core_ntohq(x64);
412 return ASL_STATUS_OK;
413 }
414
415 /* check the cache */
416 hash = asl_core_string_hash(str, len);
417
418 sp = NULL;
419 for (sx = s->string_list; sx != NULL; sx = sx->next)
420 {
421 if ((hash == sx->hash) && (!strcmp(str, sx->str)))
422 {
423 /* Move this string to the head of the list */
424 if (sp != NULL)
425 {
426 sl = s->string_list;
427 sp->next = sx->next;
428 sx->next = sl;
429 s->string_list = sx;
430 }
431
432 *out = sx->where;
433 return ASL_STATUS_OK;
434 }
435
436 sp = sx;
437 }
438
439 off = ftello(s->store);
440
441 /* Type */
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;
445
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;
450
451 /* String data (nul terminated) */
452 i = fwrite(str, len + 1, 1, s->store);
453 if (i != 1) return ASL_STATUS_WRITE_FAILED;
454
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;
458
459 sx->where = off;
460 sx->hash = hash;
461 sx->next = s->string_list;
462 memcpy(sx->str, str, len);
463
464 s->string_list = sx;
465
466 if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_count == CACHE_SIZE))
467 {
468 /* drop last (lru) string from cache */
469 sp = s->string_list;
470 sx = sp->next;
471
472 /* NB CACHE_SIZE must be > 1 */
473 while (sx->next != NULL)
474 {
475 sp = sx;
476 sx = sx->next;
477 }
478
479 sp->next = NULL;
480 free(sx);
481 }
482 else
483 {
484 s->string_count++;
485 }
486
487 *out = off;
488 return ASL_STATUS_OK;
489 }
490
491 /*
492 * Encode an aslmsg as a record structure.
493 * Creates and caches strings.
494 */
495 uint32_t
496 asl_file_save(asl_file_t *s, aslmsg msg, uint64_t *mid)
497 {
498 char *buf, *p;
499 uint32_t len, i, status;
500 file_record_t r;
501 uint64_t k, v;
502 uint64_t *kvlist;
503 off_t off;
504
505 if (s == NULL) return ASL_STATUS_INVALID_STORE;
506 if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE;
507
508 if (s->flags & ASL_FILE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY;
509
510 memset(&r, 0, sizeof(file_record_t));
511
512 r.flags = 0;
513 r.level = ASL_LEVEL_DEBUG;
514 r.pid = -1;
515 r.uid = -2;
516 r.gid = -2;
517 r.ruid = -1;
518 r.rgid = -1;
519 r.time = 0;
520 r.nano = 0;
521 r.prev = s->prev;
522 kvlist = NULL;
523
524 for (i = 0; i < msg->count; i++)
525 {
526 if (msg->key[i] == NULL)
527 {
528 continue;
529 }
530 else if (!strcmp(msg->key[i], ASL_KEY_TIME))
531 {
532 if (msg->val[i] != NULL) r.time = asl_parse_time(msg->val[i]);
533 }
534 else if (!strcmp(msg->key[i], ASL_KEY_TIME_NSEC))
535 {
536 if (msg->val[i] != NULL) r.nano = atoi(msg->val[i]);
537 }
538 else if (!strcmp(msg->key[i], ASL_KEY_HOST))
539 {
540 if (msg->val[i] != NULL)
541 {
542 status = asl_file_string_encode(s, msg->val[i], &(r.host));
543 if (status != ASL_STATUS_OK)
544 {
545 if (kvlist != NULL) free(kvlist);
546 return status;
547 }
548 }
549 }
550 else if (!strcmp(msg->key[i], ASL_KEY_SENDER))
551 {
552 if (msg->val[i] != NULL)
553 {
554 status = asl_file_string_encode(s, msg->val[i], &(r.sender));
555 if (status != ASL_STATUS_OK)
556 {
557 if (kvlist != NULL) free(kvlist);
558 return status;
559 }
560 }
561 }
562 else if (!strcmp(msg->key[i], ASL_KEY_PID))
563 {
564 if (msg->val[i] != NULL) r.pid = atoi(msg->val[i]);
565 }
566 else if (!strcmp(msg->key[i], ASL_KEY_REF_PID))
567 {
568 if (msg->val[i] != NULL) r.refpid = atoi(msg->val[i]);
569 }
570 else if (!strcmp(msg->key[i], ASL_KEY_UID))
571 {
572 if (msg->val[i] != NULL) r.uid = atoi(msg->val[i]);
573 }
574 else if (!strcmp(msg->key[i], ASL_KEY_GID))
575 {
576 if (msg->val[i] != NULL) r.gid = atoi(msg->val[i]);
577 }
578 else if (!strcmp(msg->key[i], ASL_KEY_LEVEL))
579 {
580 if (msg->val[i] != NULL) r.level = atoi(msg->val[i]);
581 }
582 else if (!strcmp(msg->key[i], ASL_KEY_MSG))
583 {
584 if (msg->val[i] != NULL)
585 {
586 status = asl_file_string_encode(s, msg->val[i], &(r.message));
587 if (status != ASL_STATUS_OK)
588 {
589 if (kvlist != NULL) free(kvlist);
590 return status;
591 }
592 }
593 }
594 else if (!strcmp(msg->key[i], ASL_KEY_FACILITY))
595 {
596 if (msg->val[i] != NULL)
597 {
598 status = asl_file_string_encode(s, msg->val[i], &(r.facility));
599 if (status != ASL_STATUS_OK)
600 {
601 if (kvlist != NULL) free(kvlist);
602 return status;
603 }
604 }
605 }
606 else if (!strcmp(msg->key[i], ASL_KEY_REF_PROC))
607 {
608 if (msg->val[i] != NULL)
609 {
610 status = asl_file_string_encode(s, msg->val[i], &(r.refproc));
611 if (status != ASL_STATUS_OK)
612 {
613 if (kvlist != NULL) free(kvlist);
614 return status;
615 }
616 }
617 }
618 else if (!strcmp(msg->key[i], ASL_KEY_SESSION))
619 {
620 if (msg->val[i] != NULL)
621 {
622 status = asl_file_string_encode(s, msg->val[i], &(r.session));
623 if (status != ASL_STATUS_OK)
624 {
625 if (kvlist != NULL) free(kvlist);
626 return status;
627 }
628 }
629 }
630 else if (!strcmp(msg->key[i], ASL_KEY_READ_UID))
631 {
632 if (((r.flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (msg->val[i] != NULL))
633 {
634 r.ruid = atoi(msg->val[i]);
635 r.flags |= ASL_MSG_FLAG_READ_UID_SET;
636 }
637 }
638 else if (!strcmp(msg->key[i], ASL_KEY_READ_GID))
639 {
640 if (((r.flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (msg->val[i] != NULL))
641 {
642 r.rgid = atoi(msg->val[i]);
643 r.flags |= ASL_MSG_FLAG_READ_GID_SET;
644 }
645 }
646 else if (!strcmp(msg->key[i], ASL_KEY_MSG_ID))
647 {
648 if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) *mid = atoll(msg->val[i]);
649 }
650 else if (!strcmp(msg->key[i], ASL_KEY_OPTION))
651 {
652 /* ignore - we don't save ASLOption */
653 }
654 else
655 {
656 status = asl_file_string_encode(s, msg->key[i], &k);
657 if (status != ASL_STATUS_OK)
658 {
659 if (kvlist != NULL) free(kvlist);
660 return status;
661 }
662
663 v = 0;
664 if (msg->val[i] != NULL)
665 {
666 status = asl_file_string_encode(s, msg->val[i], &v);
667 if (status != ASL_STATUS_OK)
668 {
669 if (kvlist != NULL) free(kvlist);
670 return status;
671 }
672 }
673
674 if (r.kvcount == 0)
675 {
676 kvlist = (uint64_t *)calloc(2, sizeof(uint64_t));
677 }
678 else
679 {
680 kvlist = (uint64_t *)reallocf(kvlist, (r.kvcount + 2) * sizeof(uint64_t));
681 }
682
683 if (kvlist == NULL)
684 {
685 return ASL_STATUS_NO_MEMORY;
686 }
687
688 kvlist[r.kvcount++] = k;
689 kvlist[r.kvcount++] = v;
690 }
691 }
692
693 len = MSG_RECORD_FIXED_LENGTH + (r.kvcount * sizeof(uint64_t));
694 buf = NULL;
695
696 /* use the scratch buffer if it exists and is large enough */
697 if ((s->scratch != NULL) && (len <= SCRATCH_BUFFER_SIZE))
698 {
699 memset(s->scratch, 0, SCRATCH_BUFFER_SIZE);
700 buf = s->scratch;
701 }
702 else
703 {
704 buf = calloc(1, len);
705 }
706
707 if (buf == NULL) return ASL_STATUS_NO_MEMORY;
708
709 if (*mid != 0)
710 {
711 r.mid = *mid;
712 }
713 else
714 {
715 r.mid = asl_core_new_msg_id(0);
716 *mid = r.mid;
717 }
718
719 p = buf;
720
721 /* Type */
722 _asl_put_16(ASL_FILE_TYPE_MSG, p);
723 p += sizeof(uint16_t);
724
725 /* Length of message (excludes type and length fields) */
726 _asl_put_32(len - RECORD_COMMON_LEN, p);
727 p += sizeof(uint32_t);
728
729 /* Message data... */
730
731 _asl_put_64(r.next, p);
732 p += sizeof(uint64_t);
733
734 _asl_put_64(r.mid, p);
735 p += sizeof(uint64_t);
736
737 _asl_put_64(r.time, p);
738 p += sizeof(uint64_t);
739
740 _asl_put_32(r.nano, p);
741 p += sizeof(uint32_t);
742
743 _asl_put_16(r.level, p);
744 p += sizeof(uint16_t);
745
746 _asl_put_16(r.flags, p);
747 p += sizeof(uint16_t);
748
749 _asl_put_32(r.pid, p);
750 p += sizeof(uint32_t);
751
752 _asl_put_32(r.uid, p);
753 p += sizeof(uint32_t);
754
755 _asl_put_32(r.gid, p);
756 p += sizeof(uint32_t);
757
758 _asl_put_32(r.ruid, p);
759 p += sizeof(uint32_t);
760
761 _asl_put_32(r.rgid, p);
762 p += sizeof(uint32_t);
763
764 _asl_put_32(r.refpid, p);
765 p += sizeof(uint32_t);
766
767 _asl_put_32(r.kvcount, p);
768 p += sizeof(uint32_t);
769
770 _asl_put_64(r.host, p);
771 p += sizeof(uint64_t);
772
773 _asl_put_64(r.sender, p);
774 p += sizeof(uint64_t);
775
776 _asl_put_64(r.facility, p);
777 p += sizeof(uint64_t);
778
779 _asl_put_64(r.message, p);
780 p += sizeof(uint64_t);
781
782 _asl_put_64(r.refproc, p);
783 p += sizeof(uint64_t);
784
785 _asl_put_64(r.session, p);
786 p += sizeof(uint64_t);
787
788 for (i = 0; i < r.kvcount; i++)
789 {
790 _asl_put_64(kvlist[i], p);
791 p += sizeof(uint64_t);
792 }
793
794 _asl_put_64(r.prev, p);
795 p += sizeof(uint64_t);
796
797 free(kvlist);
798 kvlist = NULL;
799
800 /* write record at end of file */
801 status = fseeko(s->store, 0, SEEK_END);
802 if (status != 0) return ASL_STATUS_WRITE_FAILED;
803
804 s->last = (uint64_t)ftello(s->store);
805
806 v = asl_core_htonq(s->last);
807
808 status = fwrite(buf, len, 1, s->store);
809 fflush(s->store);
810
811 /* free the buffer if it was allocated here */
812 if (buf != s->scratch) free(buf);
813
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;
817
818 status = fseeko(s->store, off, SEEK_SET);
819 if (status != 0) return ASL_STATUS_WRITE_FAILED;
820
821 status = fwrite(&v, sizeof(uint64_t), 1, s->store);
822 if (status != 1) return ASL_STATUS_WRITE_FAILED;
823
824 /* seek to DB_HEADER_LAST_OFFSET, write last record offset */
825 off = DB_HEADER_LAST_OFFSET;
826
827 status = fseeko(s->store, off, SEEK_SET);
828 if (status != 0) return ASL_STATUS_WRITE_FAILED;
829
830 status = fwrite(&v, sizeof(uint64_t), 1, s->store);
831 if (status != 1) return ASL_STATUS_WRITE_FAILED;
832
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;
836
837 s->file_size = (size_t)ftello(s->store);
838
839 s->prev = s->last;
840
841 return ASL_STATUS_OK;
842 }
843
844 static uint32_t
845 asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen)
846 {
847 static char ils[9];
848 char *p;
849 uint32_t len;
850 int status;
851 uint64_t x64;
852 uint8_t inls;
853 uint16_t type;
854 off_t off;
855
856 *out = NULL;
857 *outlen = 0;
858
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;
862
863 inls = 0;
864 x64 = asl_core_htonq(where);
865 memcpy(&inls, &x64, 1);
866 if (inls & 0x80)
867 {
868 /* inline string */
869 inls &= 0x0f;
870 if (inls > 7) return ASL_STATUS_INVALID_STORE;
871
872 p = 1 + (char *)&x64;
873 memset(ils, 0, sizeof(ils));
874 memcpy(ils, p, inls);
875 *out = strdup(ils);
876 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
877
878 *outlen = inls;
879 return ASL_STATUS_OK;
880 }
881
882 off = where;
883 if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
884
885 status = fseeko(s->store, off, SEEK_SET);
886 if (status != 0) return ASL_STATUS_READ_FAILED;
887
888 /* Type */
889 status = fread(&type, sizeof(uint16_t), 1, s->store);
890 if (status != 1) return ASL_STATUS_READ_FAILED;
891 off += sizeof(uint16_t);
892
893 /* Length */
894 len = 0;
895 status = fread(&len, sizeof(uint32_t), 1, s->store);
896 if (status != 1) return ASL_STATUS_READ_FAILED;
897 off += sizeof(uint32_t);
898
899 len = ntohl(len);
900 if ((off + len) > s->file_size) return ASL_STATUS_READ_FAILED;
901
902 *out = calloc(1, len);
903 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
904
905 status = fread(*out, len, 1, s->store);
906 if (status != 1)
907 {
908 free(*out);
909 return ASL_STATUS_READ_FAILED;
910 }
911
912 *outlen = len;
913 return ASL_STATUS_OK;
914 }
915
916 static uint16_t
917 asl_file_fetch_helper_16(asl_file_t *s, char **p, aslmsg m, const char *key)
918 {
919 uint16_t out;
920 char str[256];
921
922 out = _asl_get_16(*p);
923 *p += sizeof(uint16_t);
924
925 if ((m == NULL) || (key == NULL)) return out;
926
927 snprintf(str, sizeof(str), "%hu", out);
928 asl_set(m, key, str);
929
930 return out;
931 }
932
933 static uint32_t
934 asl_file_fetch_helper_32(asl_file_t *s, char **p, aslmsg m, const char *key, int ignore, uint32_t ignoreval)
935 {
936 uint32_t out, doit;
937 char str[256];
938
939 out = _asl_get_32(*p);
940 *p += sizeof(uint32_t);
941
942 if ((m == NULL) || (key == NULL)) return out;
943
944 doit = 1;
945 if ((ignore != 0) && (out == ignoreval)) doit = 0;
946 if (doit != 0)
947 {
948 snprintf(str, sizeof(str), "%u", out);
949 asl_set(m, key, str);
950 }
951
952 return out;
953 }
954
955 static uint64_t
956 asl_file_fetch_helper_64(asl_file_t *s, char **p, aslmsg m, const char *key)
957 {
958 uint64_t out;
959 char str[256];
960
961 out = _asl_get_64(*p);
962 *p += sizeof(uint64_t);
963
964 if ((m == NULL) || (key == NULL)) return out;
965
966 snprintf(str, sizeof(str), "%llu", out);
967 asl_set(m, key, str);
968
969 return out;
970 }
971
972 static uint64_t
973 asl_file_fetch_helper_str(asl_file_t *s, char **p, aslmsg m, const char *key, uint32_t *err)
974 {
975 uint64_t out;
976 char *val;
977 uint32_t status, len;
978
979 out = _asl_get_64(*p);
980 *p += sizeof(uint64_t);
981
982 val = NULL;
983 len = 0;
984 status = ASL_STATUS_OK;
985 if (out != 0) status = asl_file_fetch_object(s, out, &val, &len);
986
987 if (err != NULL) *err = status;
988 if ((status == ASL_STATUS_OK) && (val != NULL))
989 {
990 asl_set(m, key, val);
991 free(val);
992 }
993
994 return out;
995 }
996
997 static uint32_t
998 asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg)
999 {
1000 char *buf, *p, *k, *v;
1001 file_record_t r;
1002 uint32_t i, status, len, buflen, kvn;
1003 uint64_t x64, kv;
1004 aslmsg out;
1005 off_t off;
1006
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;
1010
1011 buf = NULL;
1012 buflen = 0;
1013 status = asl_file_fetch_object(s, where, &buf, &buflen);
1014 if ((status != ASL_STATUS_OK) || (buf == NULL))
1015 {
1016 s->cursor = 0;
1017 s->cursor_xid = 0;
1018 return status;
1019 }
1020
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))))
1024 {
1025 free(buf);
1026 s->cursor = 0;
1027 s->cursor_xid = 0;
1028 return ASL_STATUS_READ_FAILED;
1029 }
1030
1031 out = asl_new(ASL_TYPE_MSG);
1032 if (out == NULL) return ASL_STATUS_NO_MEMORY;
1033
1034 memset(&r, 0, sizeof(file_record_t));
1035 p = buf;
1036
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);
1050
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 */
1058
1059 if (status != ASL_STATUS_OK)
1060 {
1061 asl_free(out);
1062 free(buf);
1063 s->cursor = 0;
1064 s->cursor_xid = 0;
1065 return status;
1066 }
1067
1068 kvn = r.kvcount / 2;
1069
1070 for (i = 0; i < kvn; i++)
1071 {
1072 kv = _asl_get_64(p);
1073 p += sizeof(uint64_t);
1074 k = NULL;
1075 len = 0;
1076 status = asl_file_fetch_object(s, kv, &k, &len);
1077 if (status != ASL_STATUS_OK)
1078 {
1079 asl_free(out);
1080 free(buf);
1081 s->cursor = 0;
1082 s->cursor_xid = 0;
1083 return status;
1084 }
1085
1086 kv = _asl_get_64(p);
1087 p += sizeof(uint64_t);
1088 v = NULL;
1089 len = 0;
1090
1091 if (kv != 0)
1092 {
1093 status = asl_file_fetch_object(s, kv, &v, &len);
1094 if (status != ASL_STATUS_OK)
1095 {
1096 asl_free(out);
1097 free(buf);
1098 s->cursor = 0;
1099 s->cursor_xid = 0;
1100 return status;
1101 }
1102 }
1103
1104 if ((status == ASL_STATUS_OK) && (k != NULL))
1105 {
1106 asl_set(out, k, v);
1107 if (v != NULL) free(v);
1108 free(k);
1109 }
1110 }
1111
1112 r.prev = asl_file_fetch_helper_64(s, &p, NULL, NULL); /* 116 */
1113
1114 free(buf);
1115
1116 if (dir >= 0) s->cursor = r.next;
1117 else s->cursor = r.prev;
1118
1119 s->cursor_xid = 0;
1120
1121 if (s->cursor != 0)
1122 {
1123 off = s->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
1124 if (off > s->file_size)
1125 {
1126 asl_free(out);
1127 s->cursor = 0;
1128 s->cursor_xid = 0;
1129 /*
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.
1133 */
1134 return ASL_STATUS_OK;
1135 }
1136
1137 status = fseeko(s->store, off, SEEK_SET);
1138 if (status != 0)
1139 {
1140 asl_free(out);
1141 s->cursor = 0;
1142 s->cursor_xid = 0;
1143 return ASL_STATUS_READ_FAILED;
1144 }
1145
1146 status = fread(&x64, sizeof(uint64_t), 1, s->store);
1147 if (status != 1)
1148 {
1149 asl_free(out);
1150 s->cursor = 0;
1151 s->cursor_xid = 0;
1152 return ASL_STATUS_READ_FAILED;
1153 }
1154
1155 s->cursor_xid = asl_core_ntohq(x64);
1156 }
1157
1158 *msg = out;
1159 return ASL_STATUS_OK;
1160 }
1161
1162 uint32_t
1163 asl_file_open_read(const char *path, asl_file_t **s)
1164 {
1165 asl_file_t *out;
1166 FILE *f;
1167 int i;
1168 uint32_t status, vers;
1169 char buf[DB_HEADER_LEN];
1170 off_t off;
1171 asl_legacy1_t *legacy;
1172 struct stat sb;
1173
1174 memset(&sb, 0, sizeof(struct stat));
1175 if (stat(path, &sb) != 0) return ASL_STATUS_FAILED;
1176
1177 f = fopen(path, "r");
1178 if (f == NULL)
1179 {
1180 if (errno == EACCES) return ASL_STATUS_ACCESS_DENIED;
1181 return ASL_STATUS_FAILED;
1182 }
1183
1184 i = fread(buf, DB_HEADER_LEN, 1, f);
1185 if (i < 1)
1186 {
1187 fclose(f);
1188 return ASL_STATUS_INVALID_STORE;
1189 }
1190
1191 /* validate header */
1192 if (strncmp(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
1193 {
1194 fclose(f);
1195 return ASL_STATUS_INVALID_STORE;
1196 }
1197
1198 legacy = NULL;
1199
1200 vers = _asl_get_32(buf + DB_HEADER_VERS_OFFSET);
1201 if (vers == DB_VERSION_LEGACY_1)
1202 {
1203 fclose(f);
1204 status = asl_legacy1_open(path, &legacy);
1205 if (status != ASL_STATUS_OK) return status;
1206 }
1207
1208 out = (asl_file_t *)calloc(1, sizeof(asl_file_t));
1209 if (out == NULL)
1210 {
1211 fclose(f);
1212 return ASL_STATUS_NO_MEMORY;
1213 }
1214
1215 out->flags = ASL_FILE_FLAG_READ_ONLY;
1216 out->version = vers;
1217
1218 if (legacy != NULL)
1219 {
1220 out->flags |= ASL_FILE_FLAG_LEGACY_STORE;
1221 out->legacy = (void *)legacy;
1222
1223 *s = out;
1224 return ASL_STATUS_OK;
1225 }
1226
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;
1230
1231 /* detect bogus last pointer */
1232 if (out->last >= out->file_size) out->last = 0;
1233
1234 out->store = f;
1235
1236 out->cursor = out->first;
1237 if (out->cursor != 0)
1238 {
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)
1242 {
1243 fclose(f);
1244 return status;
1245 }
1246 }
1247
1248 *s = out;
1249 return ASL_STATUS_OK;
1250 }
1251
1252 static uint32_t
1253 asl_file_read_set_position_first(asl_file_t *s)
1254 {
1255 uint32_t status;
1256 off_t off;
1257
1258 s->cursor = s->first;
1259 s->cursor_xid = 0;
1260
1261 if (s->cursor == 0) return ASL_STATUS_OK;
1262
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));
1266 return status;
1267 }
1268
1269 static uint32_t
1270 asl_file_read_set_position_last(asl_file_t *s)
1271 {
1272 uint64_t next;
1273 uint32_t status;
1274 off_t off;
1275
1276 /*
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.
1281 *
1282 * Note that s->last may be zero if the file is empty.
1283 */
1284
1285 if (s->last != 0)
1286 {
1287 s->cursor = s->last;
1288 off = s->last + RECORD_COMMON_LEN + sizeof(uint64_t);
1289
1290 /* read ID of the last record */
1291 status = asl_file_read_uint64(s, off, &(s->cursor_xid));
1292 return status;
1293 }
1294
1295 /* start at the first record and iterate */
1296 s->cursor = s->first;
1297 s->cursor_xid = 0;
1298
1299 forever
1300 {
1301 off = s->cursor + RECORD_COMMON_LEN;
1302 next = 0;
1303
1304 /* read next offset */
1305 status = asl_file_read_uint64(s, off, &next);
1306 if (status != ASL_STATUS_OK) return status;
1307
1308 /* detect bogus next pointer */
1309 if (next >= s->file_size) next = 0;
1310
1311 if (next == 0)
1312 {
1313 if (s->cursor == 0) return ASL_STATUS_OK;
1314
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;
1318 }
1319
1320 s->cursor = next;
1321 }
1322 }
1323
1324 uint32_t
1325 asl_file_read_set_position(asl_file_t *s, uint32_t pos)
1326 {
1327 uint32_t len, status;
1328 off_t off;
1329
1330 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1331 if (s->version == 1) return ASL_STATUS_FAILED;
1332
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);
1335
1336 off = 0;
1337
1338 if (pos == ASL_FILE_POSITION_PREVIOUS)
1339 {
1340 if (s->cursor == s->first) return ASL_STATUS_NO_RECORDS;
1341 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1342
1343 off = s->cursor + RECORD_TYPE_LEN;
1344 status = asl_file_read_uint32(s, off, &len);
1345 if (status != ASL_STATUS_OK) return status;
1346
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);
1349 }
1350 else if (pos == ASL_FILE_POSITION_NEXT)
1351 {
1352 if (s->cursor == s->last) return ASL_STATUS_NO_RECORDS;
1353 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1354
1355 /* set offset to read the "next" field in the current record */
1356 off = s->cursor + RECORD_COMMON_LEN;
1357 }
1358 else return ASL_STATUS_INVALID_ARG;
1359
1360 s->cursor_xid = 0;
1361
1362 /*
1363 * read offset of next / previous
1364 */
1365 status = asl_file_read_uint64(s, off, &(s->cursor));
1366 if (status != ASL_STATUS_OK) return ASL_STATUS_READ_FAILED;
1367
1368 /* detect bogus next pointer */
1369 if (s->cursor >= s->file_size) s->cursor = 0;
1370
1371 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1372
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));
1376 return status;
1377 }
1378
1379 uint32_t
1380 asl_file_fetch_next(asl_file_t *s, aslmsg *msg)
1381 {
1382 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1383 if (s->version == 1) return ASL_STATUS_FAILED;
1384
1385 return asl_file_fetch_pos(s, s->cursor, 1, msg);
1386 }
1387
1388 uint32_t
1389 asl_file_fetch_previous(asl_file_t *s, aslmsg *msg)
1390 {
1391 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1392 if (s->version == 1) return ASL_STATUS_FAILED;
1393
1394 return asl_file_fetch_pos(s, s->cursor, -1, msg);
1395 }
1396
1397 uint32_t
1398 asl_file_fetch(asl_file_t *s, uint64_t mid, aslmsg *msg)
1399 {
1400 uint32_t status;
1401
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;
1405
1406 if (s->version == 1)
1407 {
1408 return asl_legacy1_fetch((asl_legacy1_t *)s->legacy, mid, msg);
1409 }
1410
1411 if (s->cursor_xid == 0)
1412 {
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;
1416 }
1417
1418 while (s->cursor_xid < mid)
1419 {
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;
1424 }
1425
1426 while (s->cursor_xid > mid)
1427 {
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;
1432 }
1433
1434 if (s->cursor_xid != mid) return ASL_STATUS_INVALID_ID;
1435
1436 return asl_file_fetch_pos(s, s->cursor, 1, msg);
1437 }
1438
1439 uint64_t
1440 asl_file_cursor(asl_file_t *s)
1441 {
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;
1445
1446 return s->cursor_xid;
1447 }
1448
1449 uint32_t
1450 asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction)
1451 {
1452 uint32_t status, d;
1453
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;
1457
1458 d = ASL_FILE_POSITION_NEXT;
1459 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1460
1461 /*
1462 * find starting point
1463 */
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;
1468
1469 while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id))))
1470 {
1471 status = asl_file_read_set_position(s, d);
1472 }
1473
1474 return status;
1475 }
1476
1477 uint32_t
1478 asl_file_match_next(asl_file_t *s, aslresponse query, asl_msg_t **msg, uint64_t *last_id, int32_t direction)
1479 {
1480 uint32_t status, d, i, do_match, did_match;
1481 aslmsg m;
1482
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;
1488
1489 *msg = NULL;
1490 do_match = 1;
1491
1492 d = ASL_FILE_POSITION_NEXT;
1493 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1494
1495 if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0;
1496
1497 m = NULL;
1498
1499 *last_id = s->cursor_xid;
1500
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;
1505
1506 did_match = 1;
1507
1508 if (do_match != 0)
1509 {
1510 did_match = 0;
1511
1512 for (i = 0; (i < query->count) && (did_match == 0); i++)
1513 {
1514 did_match = asl_msg_cmp(query->msg[i], m);
1515 }
1516 }
1517
1518 if (did_match != 0)
1519 {
1520 *msg = m;
1521 return ASL_STATUS_OK;
1522 }
1523
1524 asl_free(m);
1525 return ASL_STATUS_MATCH_FAILED;
1526 }
1527
1528 uint32_t
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)
1530 {
1531 uint32_t status, d, i, do_match, did_match, rescount;
1532 asl_msg_t *m;
1533
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;
1537
1538 if (s->version == 1)
1539 {
1540 return asl_legacy1_match((asl_legacy1_t *)s->legacy, query, res, last_id, start_id, count, direction);
1541 }
1542
1543 do_match = 1;
1544 rescount = 0;
1545
1546 d = ASL_FILE_POSITION_NEXT;
1547 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1548
1549 if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0;
1550
1551 /*
1552 * find starting point
1553 */
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;
1558
1559 while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id))))
1560 {
1561 status = asl_file_read_set_position(s, d);
1562 }
1563
1564 /*
1565 * loop through records
1566 */
1567 forever
1568 {
1569 m = NULL;
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;
1573
1574 *last_id = s->cursor_xid;
1575
1576 did_match = 1;
1577
1578 if (do_match != 0)
1579 {
1580 did_match = 0;
1581
1582 for (i = 0; (i < query->count) && (did_match == 0); i++)
1583 {
1584 did_match = asl_msg_cmp(query->msg[i], m);
1585 }
1586 }
1587
1588 if (did_match == 1)
1589 {
1590 /* append m to res */
1591 if (*res == NULL)
1592 {
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)
1597 {
1598 free(*res);
1599 return ASL_STATUS_NO_MEMORY;
1600 }
1601 }
1602 else
1603 {
1604 (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(asl_msg_t *));
1605 if ((*res)->msg == NULL)
1606 {
1607 free(*res);
1608 return ASL_STATUS_NO_MEMORY;
1609 }
1610 }
1611
1612 (*res)->msg[(*res)->count] = m;
1613 (*res)->count++;
1614
1615 rescount++;
1616 if ((count != 0) && (rescount >= count)) break;
1617 }
1618 else
1619 {
1620 asl_free(m);
1621 }
1622 }
1623
1624 /* NOT REACHED */
1625 return ASL_STATUS_OK;
1626 }
1627
1628 size_t
1629 asl_file_size(asl_file_t *s)
1630 {
1631 if (s == NULL) return 0;
1632 return s->file_size;
1633 }
1634
1635 uint64_t
1636 asl_file_ctime(asl_file_t *s)
1637 {
1638 if (s == NULL) return 0;
1639 return s->dob;
1640 }
1641
1642 void
1643 asl_file_list_close(asl_file_list_t *head)
1644 {
1645 asl_file_list_t *next;
1646
1647 while (head != NULL)
1648 {
1649 next = head->next;
1650 asl_file_close(head->file);
1651 free(head);
1652 head = next;
1653 }
1654 }
1655
1656 static void
1657 asl_file_list_free(asl_file_list_t *head)
1658 {
1659 asl_file_list_t *next;
1660
1661 while (head != NULL)
1662 {
1663 next = head->next;
1664 free(head);
1665 head = next;
1666 }
1667 }
1668
1669 asl_file_list_t *
1670 asl_file_list_insert(asl_file_list_t *list, asl_file_t *f, int32_t dir)
1671 {
1672 asl_file_list_t *a, *b, *tmp;
1673
1674 if (f == NULL) return list;
1675
1676 tmp = (asl_file_list_t *)calloc(1, sizeof(asl_file_list_t));
1677 if (tmp == NULL) return NULL;
1678 tmp->file = f;
1679
1680 if (list == NULL) return tmp;
1681
1682 a = list;
1683 if (((dir < 0) && (f->cursor_xid > a->file->cursor_xid)) || ((dir >= 0) && (f->cursor_xid < a->file->cursor_xid)))
1684 {
1685 tmp->next = list;
1686 return tmp;
1687 }
1688
1689 b = a->next;
1690 while (b != NULL)
1691 {
1692 if (((dir < 0) && (f->cursor_xid > b->file->cursor_xid)) || ((dir >= 0) && (f->cursor_xid < b->file->cursor_xid)))
1693 {
1694 tmp->next = b;
1695 a->next = tmp;
1696 return list;
1697 }
1698
1699 a = b;
1700 b = a->next;
1701 }
1702
1703 a->next = tmp;
1704 return list;
1705 }
1706
1707 asl_file_list_t *
1708 asl_file_list_add(asl_file_list_t *list, asl_file_t *f)
1709 {
1710 asl_file_list_t *tmp;
1711
1712 if (f == NULL) return list;
1713 if (f->version == 1) return list;
1714
1715 tmp = (asl_file_list_t *)calloc(1, sizeof(asl_file_list_t));
1716 if (tmp == NULL) return NULL;
1717 tmp->file = f;
1718
1719 tmp->next = list;
1720 return tmp;
1721 }
1722
1723 void *
1724 asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t direction)
1725 {
1726 uint32_t status;
1727 asl_file_list_t *n;
1728 asl_file_match_token_t *out;
1729
1730 if (list == NULL) return NULL;
1731
1732 out = (asl_file_match_token_t *)calloc(1, sizeof(asl_file_match_token_t));
1733 if (out == NULL) return NULL;
1734
1735 for (n = list; n != NULL; n = n->next)
1736 {
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;
1741
1742 out->list = asl_file_list_insert(out->list, n->file, direction);
1743 }
1744
1745 out->dir = direction;
1746 return out;
1747 }
1748
1749 uint32_t
1750 asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint32_t count)
1751 {
1752 uint32_t status, rescount;
1753 asl_file_list_t *n;
1754 asl_msg_t *m;
1755 asl_file_match_token_t *work;
1756 uint64_t last_id;
1757
1758 if (token == NULL) return ASL_STATUS_OK;
1759 if (res == NULL) return ASL_STATUS_INVALID_ARG;
1760
1761 work = (asl_file_match_token_t *)token;
1762
1763 rescount = 0;
1764 last_id = 0;
1765
1766 while ((work->list != NULL) && ((rescount < count) || (count == 0)))
1767 {
1768 m = NULL;
1769 status = asl_file_match_next(work->list->file, query, &m, &last_id, work->dir);
1770 if (m != NULL)
1771 {
1772 if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t));
1773 if (*res == NULL)
1774 {
1775 asl_file_list_free(work->list);
1776 work->list = NULL;
1777 return ASL_STATUS_NO_MEMORY;
1778 }
1779
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)
1783 {
1784 free(*res);
1785 *res = NULL;
1786 asl_file_list_free(work->list);
1787 work->list = NULL;
1788 return ASL_STATUS_NO_MEMORY;
1789 }
1790
1791 (*res)->msg[(*res)->count] = m;
1792 (*res)->count++;
1793 rescount++;
1794 }
1795
1796 if ((status != ASL_STATUS_OK) || (work->list->file->cursor_xid == 0))
1797 {
1798 n = work->list->next;
1799 free(work->list);
1800 work->list = n;
1801 }
1802
1803 if (work->list != NULL)
1804 {
1805 n = work->list->next;
1806 if (n != NULL)
1807 {
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)))
1809 {
1810 n = work->list;
1811 work->list = work->list->next;
1812 n->next = NULL;
1813 work->list = asl_file_list_insert(work->list, n->file, work->dir);
1814 free(n);
1815 }
1816 }
1817 }
1818 }
1819
1820 return ASL_STATUS_OK;
1821 }
1822
1823 void
1824 asl_file_list_match_end(void *token)
1825 {
1826 asl_file_match_token_t *work;
1827
1828 if (token == NULL) return;
1829
1830 work = (asl_file_match_token_t *)token;
1831 asl_file_list_free(work->list);
1832 work->list = NULL;
1833
1834 free(token);
1835 }
1836
1837 uint32_t
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)
1839 {
1840 uint32_t status, rescount;
1841 asl_file_list_t *files, *n;
1842 asl_msg_t *m;
1843 struct timeval now, finish;
1844
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;
1848
1849 files = NULL;
1850
1851 for (n = list; n != NULL; n = n->next)
1852 {
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;
1857
1858 files = asl_file_list_insert(files, n->file, direction);
1859 }
1860
1861 if (files == NULL)
1862 {
1863 asl_file_list_free(files);
1864 return ASL_STATUS_OK;
1865 }
1866
1867 /* start the timer if a timeout was specified */
1868 memset(&finish, 0, sizeof(struct timeval));
1869 if (usec != 0)
1870 {
1871 if (gettimeofday(&finish, NULL) == 0)
1872 {
1873 finish.tv_sec += (usec / MILLION);
1874 finish.tv_usec += (usec % MILLION);
1875 if (finish.tv_usec > MILLION)
1876 {
1877 finish.tv_usec -= MILLION;
1878 finish.tv_sec += 1;
1879 }
1880 }
1881 else
1882 {
1883 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
1884 memset(&finish, 0, sizeof(struct timeval));
1885 }
1886 }
1887
1888 rescount = 0;
1889 while ((files != NULL) && ((rescount < count) || (count == 0)))
1890 {
1891 m = NULL;
1892 status = asl_file_match_next(files->file, query, &m, last_id, direction);
1893 if (m != NULL)
1894 {
1895 if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t));
1896 if (*res == NULL)
1897 {
1898 asl_file_list_free(files);
1899 return ASL_STATUS_NO_MEMORY;
1900 }
1901
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)
1905 {
1906 free(*res);
1907 *res = NULL;
1908 asl_file_list_free(files);
1909 return ASL_STATUS_NO_MEMORY;
1910 }
1911
1912 (*res)->msg[(*res)->count] = m;
1913 (*res)->count++;
1914 rescount++;
1915 }
1916
1917 if (files->file->cursor_xid == 0)
1918 {
1919 n = files->next;
1920 free(files);
1921 files = n;
1922 }
1923
1924 if (files != NULL)
1925 {
1926 n = files->next;
1927 if (n != NULL)
1928 {
1929 if (((direction < 0) && (files->file->cursor_xid <= n->file->cursor_xid)) || ((direction >= 0) && (files->file->cursor_xid > n->file->cursor_xid)))
1930 {
1931 n = files;
1932 files = files->next;
1933 n->next = NULL;
1934 files = asl_file_list_insert(files, n->file, direction);
1935 free(n);
1936 }
1937 }
1938 }
1939
1940 /* check the timer */
1941 if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0))
1942 {
1943 if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) break;
1944 }
1945 }
1946
1947 asl_file_list_free(files);
1948 return ASL_STATUS_OK;
1949 }
1950
1951 uint32_t
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)
1953 {
1954 return asl_file_list_match_timeout(list, query, res, last_id, start_id, count, direction, 0);
1955 }