2 * Copyright (c) 2007-2008 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@
26 #include <asl_legacy1.h>
27 #include <asl_private.h>
31 #include <sys/errno.h>
33 #include <membership.h>
34 #include <mach/mach.h>
35 #include <sys/syslimits.h>
36 #include <sys/types.h>
40 #define forever for(;;)
42 #define FILE_MODE 0600
44 #define DB_RECORD_LEN 80
46 #define DB_HEADER_COOKIE_OFFSET 0
47 #define DB_HEADER_VERS_OFFSET 12
49 #define DB_TYPE_EMPTY 0
50 #define DB_TYPE_HEADER 1
51 #define DB_TYPE_MESSAGE 2
52 #define DB_TYPE_KVLIST 3
53 #define DB_TYPE_STRING 4
54 #define DB_TYPE_STRCONT 5
57 * Magic Cookie for database files.
58 * MAXIMUM 12 CHARS! (DB_HEADER_VERS_OFFSET)
60 #define ASL_DB_COOKIE "ASL DB"
61 #define ASL_DB_COOKIE_LEN 6
63 #define ASL_INDEX_NULL 0xffffffff
65 #define DB_HLEN_EMPTY 0
66 #define DB_HLEN_HEADER 13
67 #define DB_HLEN_MESSAGE 13
68 #define DB_HLEN_KVLIST 9
69 #define DB_HLEN_STRING 25
70 #define DB_HLEN_STRCONT 5
72 #define MSG_OFF_KEY_TYPE 0
73 #define MSG_OFF_KEY_NEXT 1
74 #define MSG_OFF_KEY_ID 5
75 #define MSG_OFF_KEY_RUID 13
76 #define MSG_OFF_KEY_RGID 17
77 #define MSG_OFF_KEY_TIME 21
78 #define MSG_OFF_KEY_HOST 29
79 #define MSG_OFF_KEY_SENDER 37
80 #define MSG_OFF_KEY_FACILITY 45
81 #define MSG_OFF_KEY_LEVEL 53
82 #define MSG_OFF_KEY_PID 57
83 #define MSG_OFF_KEY_UID 61
84 #define MSG_OFF_KEY_GID 65
85 #define MSG_OFF_KEY_MSG 69
86 #define MSG_OFF_KEY_FLAGS 77
88 extern time_t asl_parse_time(const char *str
);
89 extern int asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
);
91 #define asl_msg_list_t asl_search_result_t
93 #define PMSG_SEL_TIME 0x0001
94 #define PMSG_SEL_HOST 0x0002
95 #define PMSG_SEL_SENDER 0x0004
96 #define PMSG_SEL_FACILITY 0x0008
97 #define PMSG_SEL_MESSAGE 0x0010
98 #define PMSG_SEL_LEVEL 0x0020
99 #define PMSG_SEL_PID 0x0040
100 #define PMSG_SEL_UID 0x0080
101 #define PMSG_SEL_GID 0x0100
102 #define PMSG_SEL_RUID 0x0200
103 #define PMSG_SEL_RGID 0x0400
105 #define PMSG_FETCH_ALL 0
106 #define PMSG_FETCH_STD 1
107 #define PMSG_FETCH_KV 2
109 #define Q_NULL 100001
110 #define Q_FAST 100002
111 #define Q_SLOW 100003
112 #define Q_FAIL 100004
136 _asl_htonq(uint64_t n
)
138 #ifdef __BIG_ENDIAN__
150 x
.l
[0] = htonl(x
.l
[1]);
158 _asl_ntohq(uint64_t n
)
160 #ifdef __BIG_ENDIAN__
172 x
.l
[0] = ntohl(x
.l
[1]);
203 return _asl_ntohq(x
);
206 #define header_get_next(h) _asl_get_32(h + 1)
207 #define header_get_id(h) _asl_get_64(h + 5)
208 #define header_get_hash(h) _asl_get_32(h + 17)
211 * callback for sorting slotlist
212 * primary sort is by xid
213 * secondary sort is by slot, which happens when xid is 0
214 * this allows us to quickly find xids (using binary search on the xid key)
215 * it's also used to find slots quickly from record_chain_free()
218 slot_comp(const void *a
, const void *b
)
220 asl_legacy1_slot_info_t
*ai
, *bi
;
224 if (b
== NULL
) return 0;
228 if (b
== NULL
) return 1;
230 ai
= (asl_legacy1_slot_info_t
*)a
;
231 bi
= (asl_legacy1_slot_info_t
*)b
;
233 if (ai
->xid
< bi
->xid
) return -1;
235 if (ai
->xid
== bi
->xid
)
237 if (ai
->slot
< bi
->slot
) return -1;
238 if (ai
->slot
== bi
->slot
) return 0;
245 /* find an xid in the slot list */
247 slotlist_find(asl_legacy1_t
*s
, uint64_t xid
, int32_t direction
)
249 uint32_t top
, bot
, mid
, range
;
251 if (s
== NULL
) return ASL_INDEX_NULL
;
252 if (s
->slotlist_count
== 0) return ASL_INDEX_NULL
;
253 if (xid
== 0) return ASL_INDEX_NULL
;
255 top
= s
->slotlist_count
- 1;
262 if (xid
== s
->slotlist
[mid
].xid
) return mid
;
263 else if (xid
< s
->slotlist
[mid
].xid
) top
= mid
;
267 mid
= bot
+ (range
/ 2);
270 if (xid
== s
->slotlist
[top
].xid
) return top
;
271 if (xid
== s
->slotlist
[bot
].xid
) return bot
;
273 if (direction
== 0) return ASL_INDEX_NULL
;
274 if (direction
< 0) return bot
;
279 slotlist_init(asl_legacy1_t
*s
, uint32_t count
)
281 uint32_t i
, si
, status
, hash
, addslot
;
284 char tmp
[DB_RECORD_LEN
];
286 /* Start at first slot after the header */
287 status
= fseek(s
->db
, DB_RECORD_LEN
, SEEK_SET
);
288 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
290 s
->slotlist
= (asl_legacy1_slot_info_t
*)calloc(count
, sizeof(asl_legacy1_slot_info_t
));
291 if (s
->slotlist
== NULL
) return ASL_STATUS_NO_MEMORY
;
295 for (i
= 1; i
< count
; i
++)
297 status
= fread(tmp
, DB_RECORD_LEN
, 1, s
->db
);
298 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
305 if (t
== DB_TYPE_EMPTY
) addslot
= 1;
307 if (t
== DB_TYPE_STRING
)
310 xid
= header_get_id(tmp
);
311 hash
= header_get_hash(tmp
);
314 if (t
== DB_TYPE_MESSAGE
)
317 xid
= header_get_id(tmp
);
322 s
->slotlist
[si
].type
= t
;
323 s
->slotlist
[si
].slot
= i
;
324 s
->slotlist
[si
].xid
= xid
;
325 s
->slotlist
[si
].hash
= hash
;
330 s
->slotlist
= (asl_legacy1_slot_info_t
*)reallocf(s
->slotlist
, si
* sizeof(asl_legacy1_slot_info_t
));
331 if (s
->slotlist
== NULL
) return ASL_STATUS_NO_MEMORY
;
332 s
->slotlist_count
= si
;
334 /* slotlist is sorted by xid */
335 qsort((void *)s
->slotlist
, s
->slotlist_count
, sizeof(asl_legacy1_slot_info_t
), slot_comp
);
337 return ASL_STATUS_OK
;
341 asl_legacy1_open(const char *path
, asl_legacy1_t
**out
)
346 char cbuf
[DB_RECORD_LEN
];
350 memset(&sb
, 0, sizeof(struct stat
));
351 status
= stat(path
, &sb
);
352 if (status
< 0) return ASL_STATUS_FAILED
;
356 s
= (asl_legacy1_t
*)calloc(1, sizeof(asl_legacy1_t
));
357 if (s
== NULL
) return ASL_STATUS_NO_MEMORY
;
359 s
->db
= fopen(path
, "r");
363 return ASL_STATUS_INVALID_STORE
;
366 memset(cbuf
, 0, DB_RECORD_LEN
);
367 status
= fread(cbuf
, DB_RECORD_LEN
, 1, s
->db
);
372 return ASL_STATUS_READ_FAILED
;
375 /* Check the database Magic Cookie */
376 if (strncmp(cbuf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
380 return ASL_STATUS_INVALID_STORE
;
383 count
= fsize
/ DB_RECORD_LEN
;
385 status
= slotlist_init(s
, count
);
388 return ASL_STATUS_OK
;
392 asl_legacy1_close(asl_legacy1_t
*s
)
394 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
396 if (s
->slotlist
!= NULL
) free(s
->slotlist
);
397 if (s
->db
!= NULL
) fclose(s
->db
);
400 return ASL_STATUS_OK
;
404 string_fetch_slot(asl_legacy1_t
*s
, uint32_t slot
, char **out
)
408 uint32_t status
, next
, len
, x
, remaining
;
409 char *outstr
, *p
, tmp
[DB_RECORD_LEN
];
411 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
412 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
415 offset
= slot
* DB_RECORD_LEN
;
416 status
= fseek(s
->db
, offset
, SEEK_SET
);
418 if (status
< 0) return ASL_STATUS_READ_FAILED
;
420 status
= fread(tmp
, DB_RECORD_LEN
, 1, s
->db
);
421 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
424 if (type
!= DB_TYPE_STRING
) return ASL_STATUS_INVALID_STRING
;
426 len
= _asl_get_32(tmp
+ 21);
427 if (len
== 0) return ASL_STATUS_OK
;
429 next
= header_get_next(tmp
);
431 outstr
= calloc(1, len
);
432 if (outstr
== NULL
) return ASL_STATUS_NO_MEMORY
;
437 x
= DB_RECORD_LEN
- DB_HLEN_STRING
;
438 if (x
> remaining
) x
= remaining
;
440 memcpy(p
, tmp
+ DB_HLEN_STRING
, x
);
444 while ((next
!= 0) && (remaining
> 0))
446 offset
= next
* DB_RECORD_LEN
;
447 status
= fseek(s
->db
, offset
, SEEK_SET
);
452 return ASL_STATUS_READ_FAILED
;
455 status
= fread(tmp
, DB_RECORD_LEN
, 1, s
->db
);
459 return ASL_STATUS_READ_FAILED
;
462 next
= header_get_next(tmp
);
464 x
= DB_RECORD_LEN
- DB_HLEN_STRCONT
;
465 if (x
> remaining
) x
= remaining
;
467 memcpy(p
, tmp
+ DB_HLEN_STRCONT
, x
);
472 if ((next
!= 0) || (remaining
!= 0))
475 return ASL_STATUS_READ_FAILED
;
479 return ASL_STATUS_OK
;
483 string_fetch_sid(asl_legacy1_t
*s
, uint64_t sid
, char **out
)
485 uint32_t i
, len
, ref
;
490 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
491 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
494 if (sid
== ASL_REF_NULL
) return ASL_STATUS_OK
;
499 nsid
= _asl_htonq(sid
);
500 memcpy(&inls
, &nsid
, 1);
506 *out
= calloc(1, len
);
507 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
508 p
= 1 + (char *)&nsid
;
509 memcpy(*out
, p
, len
);
510 return ASL_STATUS_OK
;
513 /* Find the string in the database */
514 i
= slotlist_find(s
, sid
, 0);
515 if (i
== ASL_INDEX_NULL
) return ASL_STATUS_NOT_FOUND
;
517 return string_fetch_slot(s
, s
->slotlist
[i
].slot
, out
);
521 pmsg_fetch(asl_legacy1_t
*s
, uint32_t slot
, uint32_t action
, pmsg_t
**pmsg
)
524 uint32_t status
, i
, n
, v32
, next
;
529 char *p
, tmp
[DB_RECORD_LEN
];
531 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
532 if (pmsg
== NULL
) return ASL_STATUS_INVALID_ARG
;
536 if ((action
== PMSG_FETCH_ALL
) || (action
== PMSG_FETCH_STD
))
540 offset
= slot
* DB_RECORD_LEN
;
541 status
= fseek(s
->db
, offset
, SEEK_SET
);
543 if (status
< 0) return ASL_STATUS_READ_FAILED
;
545 status
= fread(tmp
, DB_RECORD_LEN
, 1, s
->db
);
546 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
548 msgid
= _asl_get_64(tmp
+ MSG_OFF_KEY_ID
);
549 msgu
= _asl_get_32(tmp
+ MSG_OFF_KEY_RUID
);
550 msgg
= _asl_get_32(tmp
+ MSG_OFF_KEY_RGID
);
551 flags
= _asl_get_16(tmp
+ MSG_OFF_KEY_FLAGS
);
553 out
= (pmsg_t
*)calloc(1, sizeof(pmsg_t
));
554 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
569 out
->time
= _asl_get_64(p
);
573 out
->host
= _asl_get_64(p
);
577 out
->sender
= _asl_get_64(p
);
581 out
->facility
= _asl_get_64(p
);
585 out
->level
= _asl_get_32(p
);
589 out
->pid
= _asl_get_32(p
);
593 out
->uid
= _asl_get_32(p
);
597 out
->gid
= _asl_get_32(p
);
601 out
->message
= _asl_get_64(p
);
604 next
= header_get_next(tmp
);
607 if (action
== PMSG_FETCH_STD
)
609 /* caller only wants "standard" keys */
611 return ASL_STATUS_OK
;
626 offset
= next
* DB_RECORD_LEN
;
627 status
= fseek(s
->db
, offset
, SEEK_SET
);
632 return ASL_STATUS_READ_FAILED
;
635 status
= fread(tmp
, DB_RECORD_LEN
, 1, s
->db
);
640 return ASL_STATUS_READ_FAILED
;
643 if (out
->kvcount
== 0)
645 v32
= _asl_get_32(tmp
+ 5);
646 out
->kvcount
= v32
* 2;
647 out
->kvlist
= (uint64_t *)calloc(out
->kvcount
, sizeof(uint64_t));
648 if (out
->kvlist
== NULL
)
652 return ASL_STATUS_NO_MEMORY
;
658 for (i
= 0; (i
< 4) && (n
< out
->kvcount
); i
++)
660 out
->kvlist
[n
++] = _asl_get_64(p
);
663 out
->kvlist
[n
++] = _asl_get_64(p
);
667 next
= header_get_next(tmp
);
670 return ASL_STATUS_OK
;
674 pmsg_match(asl_legacy1_t
*s
, pmsg_t
*q
, pmsg_t
*m
)
678 if (s
== NULL
) return 0;
679 if (q
== NULL
) return 1;
680 if (m
== NULL
) return 0;
682 if (q
->kselect
& PMSG_SEL_TIME
)
684 if (q
->time
== ASL_REF_NULL
) return 0;
685 if ((q
->vselect
& PMSG_SEL_TIME
) && (q
->time
!= m
->time
)) return 0;
688 if (q
->kselect
& PMSG_SEL_HOST
)
690 if (q
->host
== ASL_REF_NULL
) return 0;
691 if ((q
->vselect
& PMSG_SEL_HOST
) && (q
->host
!= m
->host
)) return 0;
694 if (q
->kselect
& PMSG_SEL_SENDER
)
696 if (q
->sender
== ASL_REF_NULL
) return 0;
697 if ((q
->vselect
& PMSG_SEL_SENDER
) && (q
->sender
!= m
->sender
)) return 0;
700 if (q
->kselect
& PMSG_SEL_FACILITY
)
702 if (q
->facility
== ASL_REF_NULL
) return 0;
703 if ((q
->vselect
& PMSG_SEL_FACILITY
) && (q
->facility
!= m
->facility
)) return 0;
706 if (q
->kselect
& PMSG_SEL_MESSAGE
)
708 if (q
->message
== ASL_REF_NULL
) return 0;
709 if ((q
->vselect
& PMSG_SEL_MESSAGE
) && (q
->message
!= m
->message
)) return 0;
712 if (q
->kselect
& PMSG_SEL_LEVEL
)
714 if (q
->level
== ASL_INDEX_NULL
) return 0;
715 if ((q
->vselect
& PMSG_SEL_LEVEL
) && (q
->level
!= m
->level
)) return 0;
718 if (q
->kselect
& PMSG_SEL_PID
)
720 if (q
->pid
== -1) return 0;
721 if ((q
->vselect
& PMSG_SEL_PID
) && (q
->pid
!= m
->pid
)) return 0;
724 if (q
->kselect
& PMSG_SEL_UID
)
726 if (q
->uid
== -2) return 0;
727 if ((q
->vselect
& PMSG_SEL_UID
) && (q
->uid
!= m
->uid
)) return 0;
730 if (q
->kselect
& PMSG_SEL_GID
)
732 if (q
->gid
== -2) return 0;
733 if ((q
->vselect
& PMSG_SEL_GID
) && (q
->gid
!= m
->gid
)) return 0;
736 if (q
->kselect
& PMSG_SEL_RUID
)
738 if (q
->ruid
== -1) return 0;
739 if ((q
->vselect
& PMSG_SEL_RUID
) && (q
->ruid
!= m
->ruid
)) return 0;
742 if (q
->kselect
& PMSG_SEL_RGID
)
744 if (q
->rgid
== -1) return 0;
745 if ((q
->vselect
& PMSG_SEL_RGID
) && (q
->rgid
!= m
->rgid
)) return 0;
748 for (i
= 0; i
< q
->kvcount
; i
+= 2)
750 for (j
= 0; j
< m
->kvcount
; j
+= 2)
752 if (q
->kvlist
[i
] == m
->kvlist
[j
])
754 if (q
->kvlist
[i
+ 1] == m
->kvlist
[j
+ 1]) break;
759 if (j
>= m
->kvcount
) return 0;
768 if (p
== NULL
) return;
769 if (p
->kvlist
!= NULL
) free(p
->kvlist
);
774 pmsg_fetch_by_id(asl_legacy1_t
*s
, uint64_t msgid
, pmsg_t
**pmsg
, uint32_t *slot
)
778 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
779 if (msgid
== ASL_REF_NULL
) return ASL_STATUS_INVALID_ARG
;
780 if (slot
== NULL
) return ASL_STATUS_INVALID_ARG
;
782 *slot
= ASL_INDEX_NULL
;
784 i
= slotlist_find(s
, msgid
, 0);
785 if (i
== ASL_INDEX_NULL
) return ASL_STATUS_INVALID_ID
;
787 *slot
= s
->slotlist
[i
].slot
;
789 /* read the message */
791 status
= pmsg_fetch(s
, s
->slotlist
[i
].slot
, PMSG_FETCH_ALL
, pmsg
);
792 if (status
!= ASL_STATUS_OK
) return status
;
793 if (pmsg
== NULL
) return ASL_STATUS_FAILED
;
799 msg_decode(asl_legacy1_t
*s
, pmsg_t
*pmsg
, asl_msg_t
**out
)
801 uint32_t status
, i
, n
;
805 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
806 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
807 if (pmsg
== NULL
) return ASL_STATUS_INVALID_ARG
;
811 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
812 if (msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
814 msg
->type
= ASL_TYPE_MSG
;
816 if (pmsg
->time
!= ASL_REF_NULL
) msg
->count
++;
817 if (pmsg
->host
!= ASL_REF_NULL
) msg
->count
++;
818 if (pmsg
->sender
!= ASL_REF_NULL
) msg
->count
++;
819 if (pmsg
->facility
!= ASL_REF_NULL
) msg
->count
++;
820 if (pmsg
->message
!= ASL_REF_NULL
) msg
->count
++;
821 if (pmsg
->level
!= ASL_INDEX_NULL
) msg
->count
++;
822 if (pmsg
->pid
!= -1) msg
->count
++;
823 if (pmsg
->uid
!= -2) msg
->count
++;
824 if (pmsg
->gid
!= -2) msg
->count
++;
825 if (pmsg
->ruid
!= -1) msg
->count
++;
826 if (pmsg
->rgid
!= -1) msg
->count
++;
828 msg
->count
+= pmsg
->kvcount
/ 2;
833 return ASL_STATUS_INVALID_MESSAGE
;
839 msg
->key
= (char **)calloc(msg
->count
, sizeof(char *));
840 if (msg
->key
== NULL
)
843 return ASL_STATUS_NO_MEMORY
;
846 msg
->val
= (char **)calloc(msg
->count
, sizeof(char *));
847 if (msg
->val
== NULL
)
851 return ASL_STATUS_NO_MEMORY
;
857 if (pmsg
->time
!= ASL_REF_NULL
)
859 msg
->key
[n
] = strdup(ASL_KEY_TIME
);
860 if (msg
->key
[n
] == NULL
)
863 return ASL_STATUS_NO_MEMORY
;
866 asprintf(&(msg
->val
[n
]), "%llu", pmsg
->time
);
867 if (msg
->val
[n
] == NULL
)
870 return ASL_STATUS_NO_MEMORY
;
876 if (pmsg
->host
!= ASL_REF_NULL
)
878 msg
->key
[n
] = strdup(ASL_KEY_HOST
);
879 if (msg
->key
[n
] == NULL
)
882 return ASL_STATUS_NO_MEMORY
;
885 status
= string_fetch_sid(s
, pmsg
->host
, &(msg
->val
[n
]));
890 if (pmsg
->sender
!= ASL_REF_NULL
)
892 msg
->key
[n
] = strdup(ASL_KEY_SENDER
);
893 if (msg
->key
[n
] == NULL
)
896 return ASL_STATUS_NO_MEMORY
;
899 status
= string_fetch_sid(s
, pmsg
->sender
, &(msg
->val
[n
]));
904 if (pmsg
->facility
!= ASL_REF_NULL
)
906 msg
->key
[n
] = strdup(ASL_KEY_FACILITY
);
907 if (msg
->key
[n
] == NULL
)
910 return ASL_STATUS_NO_MEMORY
;
913 status
= string_fetch_sid(s
, pmsg
->facility
, &(msg
->val
[n
]));
918 if (pmsg
->level
!= ASL_INDEX_NULL
)
920 msg
->key
[n
] = strdup(ASL_KEY_LEVEL
);
921 if (msg
->key
[n
] == NULL
)
924 return ASL_STATUS_NO_MEMORY
;
927 asprintf(&(msg
->val
[n
]), "%u", pmsg
->level
);
928 if (msg
->val
[n
] == NULL
)
931 return ASL_STATUS_NO_MEMORY
;
939 msg
->key
[n
] = strdup(ASL_KEY_PID
);
940 if (msg
->key
[n
] == NULL
)
943 return ASL_STATUS_NO_MEMORY
;
946 asprintf(&(msg
->val
[n
]), "%d", pmsg
->pid
);
947 if (msg
->val
[n
] == NULL
)
950 return ASL_STATUS_NO_MEMORY
;
958 msg
->key
[n
] = strdup(ASL_KEY_UID
);
959 if (msg
->key
[n
] == NULL
)
962 return ASL_STATUS_NO_MEMORY
;
965 asprintf(&(msg
->val
[n
]), "%d", pmsg
->uid
);
966 if (msg
->val
[n
] == NULL
)
969 return ASL_STATUS_NO_MEMORY
;
977 msg
->key
[n
] = strdup(ASL_KEY_GID
);
978 if (msg
->key
[n
] == NULL
)
981 return ASL_STATUS_NO_MEMORY
;
984 asprintf(&(msg
->val
[n
]), "%d", pmsg
->gid
);
985 if (msg
->val
[n
] == NULL
)
988 return ASL_STATUS_NO_MEMORY
;
994 if (pmsg
->message
!= ASL_REF_NULL
)
996 msg
->key
[n
] = strdup(ASL_KEY_MSG
);
997 if (msg
->key
[n
] == NULL
)
1000 return ASL_STATUS_NO_MEMORY
;
1003 status
= string_fetch_sid(s
, pmsg
->message
, &(msg
->val
[n
]));
1008 if (pmsg
->ruid
!= -1)
1010 msg
->key
[n
] = strdup(ASL_KEY_READ_UID
);
1011 if (msg
->key
[n
] == NULL
)
1014 return ASL_STATUS_NO_MEMORY
;
1017 asprintf(&(msg
->val
[n
]), "%d", pmsg
->ruid
);
1018 if (msg
->val
[n
] == NULL
)
1021 return ASL_STATUS_NO_MEMORY
;
1027 if (pmsg
->rgid
!= -1)
1029 msg
->key
[n
] = strdup(ASL_KEY_READ_GID
);
1030 if (msg
->key
[n
] == NULL
)
1033 return ASL_STATUS_NO_MEMORY
;
1036 asprintf(&(msg
->val
[n
]), "%d", pmsg
->rgid
);
1037 if (msg
->val
[n
] == NULL
)
1040 return ASL_STATUS_NO_MEMORY
;
1046 msg
->key
[n
] = strdup(ASL_KEY_MSG_ID
);
1047 if (msg
->key
[n
] == NULL
)
1050 return ASL_STATUS_NO_MEMORY
;
1053 asprintf(&(msg
->val
[n
]), "%llu", pmsg
->msgid
);
1054 if (msg
->val
[n
] == NULL
)
1057 return ASL_STATUS_NO_MEMORY
;
1061 /* Key - Value List */
1062 for (i
= 0; i
< pmsg
->kvcount
; i
++)
1065 status
= string_fetch_sid(s
, pmsg
->kvlist
[i
++], &key
);
1066 if (status
!= ASL_STATUS_OK
)
1068 if (key
!= NULL
) free(key
);
1073 status
= string_fetch_sid(s
, pmsg
->kvlist
[i
], &val
);
1074 if (status
!= ASL_STATUS_OK
)
1076 if (key
!= NULL
) free(key
);
1077 if (val
!= NULL
) free(val
);
1087 return ASL_STATUS_OK
;
1091 * Finds string either in the string cache or in the database
1094 store_string_find(asl_legacy1_t
*s
, uint32_t hash
, const char *str
, uint32_t *index
)
1099 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1100 if (str
== NULL
) return ASL_STATUS_INVALID_ARG
;
1101 if (index
== NULL
) return ASL_STATUS_INVALID_ARG
;
1102 if (s
->slotlist
== NULL
) return ASL_STATUS_FAILED
;
1104 /* check the database */
1105 for (i
= 0; i
< s
->slotlist_count
; i
++)
1107 if ((s
->slotlist
[i
].type
!= DB_TYPE_STRING
) || (s
->slotlist
[i
].hash
!= hash
)) continue;
1109 /* read the whole string */
1111 status
= string_fetch_slot(s
, s
->slotlist
[i
].slot
, &tmp
);
1112 if (status
!= ASL_STATUS_OK
) return status
;
1113 if (tmp
== NULL
) return ASL_STATUS_FAILED
;
1115 status
= strcmp(tmp
, str
);
1117 if (status
!= 0) continue;
1121 return ASL_STATUS_OK
;
1124 return ASL_STATUS_FAILED
;
1128 * Looks up a string ID number.
1131 string_lookup(asl_legacy1_t
*s
, const char *str
)
1133 uint32_t status
, hash
, index
, slot
, len
;
1138 if (s
== NULL
) return ASL_REF_NULL
;
1139 if (str
== NULL
) return ASL_REF_NULL
;
1142 index
= ASL_INDEX_NULL
;
1143 slot
= ASL_INDEX_NULL
;
1154 memcpy(p
, &inls
, 1);
1155 memcpy(p
+ 1, str
, len
);
1156 sid
= _asl_ntohq(nsid
);
1160 hash
= asl_core_string_hash(str
, len
);
1162 /* check the database */
1163 status
= store_string_find(s
, hash
, str
, &index
);
1164 if (status
== ASL_STATUS_OK
)
1166 if (index
== ASL_INDEX_NULL
) return ASL_REF_NULL
;
1167 return s
->slotlist
[index
].xid
;
1170 return ASL_REF_NULL
;
1174 asl_legacy1_fetch(asl_legacy1_t
*s
, uint64_t msgid
, asl_msg_t
**msg
)
1176 uint32_t status
, slot
;
1179 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1180 if (msgid
== ASL_REF_NULL
) return ASL_STATUS_INVALID_ARG
;
1183 slot
= ASL_INDEX_NULL
;
1185 status
= pmsg_fetch_by_id(s
, msgid
, &pmsg
, &slot
);
1186 if (status
!= ASL_STATUS_OK
) return status
;
1187 if (pmsg
== NULL
) return ASL_STATUS_FAILED
;
1189 status
= msg_decode(s
, pmsg
, msg
);
1196 query_to_pmsg(asl_legacy1_t
*s
, asl_msg_t
*q
, pmsg_t
**p
)
1200 uint64_t ksid
, vsid
;
1202 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1203 if (p
== NULL
) return ASL_STATUS_INVALID_ARG
;
1205 if (q
== NULL
) return Q_NULL
;
1206 if (q
->count
== 0) return Q_NULL
;
1212 for (i
= 0; i
< q
->count
; i
++) if (q
->op
[i
] != ASL_QUERY_OP_EQUAL
) return Q_SLOW
;
1215 out
= (pmsg_t
*)calloc(1, sizeof(pmsg_t
));
1216 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1218 for (i
= 0; i
< q
->count
; i
++)
1220 if (q
->key
[i
] == NULL
) continue;
1222 else if (!strcmp(q
->key
[i
], ASL_KEY_TIME
))
1224 if (out
->kselect
& PMSG_SEL_TIME
)
1230 out
->kselect
|= PMSG_SEL_TIME
;
1231 if (q
->val
[i
] != NULL
)
1233 out
->vselect
|= PMSG_SEL_TIME
;
1234 out
->time
= asl_parse_time(q
->val
[i
]);
1237 else if (!strcmp(q
->key
[i
], ASL_KEY_HOST
))
1239 if (out
->kselect
& PMSG_SEL_HOST
)
1245 out
->kselect
|= PMSG_SEL_HOST
;
1246 if (q
->val
[i
] != NULL
)
1248 out
->vselect
|= PMSG_SEL_HOST
;
1249 out
->host
= string_lookup(s
, q
->val
[i
]);
1250 if (out
->host
== ASL_REF_NULL
)
1257 else if (!strcmp(q
->key
[i
], ASL_KEY_SENDER
))
1259 if (out
->kselect
& PMSG_SEL_SENDER
)
1265 out
->kselect
|= PMSG_SEL_SENDER
;
1266 if (q
->val
[i
] != NULL
)
1268 out
->vselect
|= PMSG_SEL_SENDER
;
1269 out
->sender
= string_lookup(s
, q
->val
[i
]);
1270 if (out
->sender
== ASL_REF_NULL
)
1277 else if (!strcmp(q
->key
[i
], ASL_KEY_PID
))
1279 if (out
->kselect
& PMSG_SEL_PID
)
1285 out
->kselect
|= PMSG_SEL_PID
;
1286 if (q
->val
[i
] != NULL
)
1288 out
->vselect
|= PMSG_SEL_PID
;
1289 out
->pid
= atoi(q
->val
[i
]);
1292 else if (!strcmp(q
->key
[i
], ASL_KEY_UID
))
1294 if (out
->kselect
& PMSG_SEL_UID
)
1300 out
->kselect
|= PMSG_SEL_UID
;
1301 if (q
->val
[i
] != NULL
)
1303 out
->vselect
|= PMSG_SEL_UID
;
1304 out
->uid
= atoi(q
->val
[i
]);
1307 else if (!strcmp(q
->key
[i
], ASL_KEY_GID
))
1309 if (out
->kselect
& PMSG_SEL_GID
)
1315 out
->kselect
|= PMSG_SEL_GID
;
1316 if (q
->val
[i
] != NULL
)
1318 out
->vselect
|= PMSG_SEL_GID
;
1319 out
->gid
= atoi(q
->val
[i
]);
1322 else if (!strcmp(q
->key
[i
], ASL_KEY_LEVEL
))
1324 if (out
->kselect
& PMSG_SEL_LEVEL
)
1330 out
->kselect
|= PMSG_SEL_LEVEL
;
1331 if (q
->val
[i
] != NULL
)
1333 out
->vselect
|= PMSG_SEL_LEVEL
;
1334 out
->level
= atoi(q
->val
[i
]);
1337 else if (!strcmp(q
->key
[i
], ASL_KEY_MSG
))
1339 if (out
->kselect
& PMSG_SEL_MESSAGE
)
1345 out
->kselect
|= PMSG_SEL_MESSAGE
;
1346 if (q
->val
[i
] != NULL
)
1348 out
->vselect
|= PMSG_SEL_MESSAGE
;
1349 out
->message
= string_lookup(s
, q
->val
[i
]);
1350 if (out
->message
== ASL_REF_NULL
)
1357 else if (!strcmp(q
->key
[i
], ASL_KEY_FACILITY
))
1359 if (out
->kselect
& PMSG_SEL_FACILITY
)
1365 out
->kselect
|= PMSG_SEL_FACILITY
;
1366 if (q
->val
[i
] != NULL
)
1368 out
->vselect
|= PMSG_SEL_FACILITY
;
1369 out
->facility
= string_lookup(s
, q
->val
[i
]);
1370 if (out
->facility
== ASL_REF_NULL
)
1377 else if (!strcmp(q
->key
[i
], ASL_KEY_READ_UID
))
1379 if (out
->kselect
& PMSG_SEL_RUID
)
1385 out
->kselect
|= PMSG_SEL_RUID
;
1386 if (q
->val
[i
] != NULL
)
1388 out
->vselect
|= PMSG_SEL_RUID
;
1389 out
->ruid
= atoi(q
->val
[i
]);
1392 else if (!strcmp(q
->key
[i
], ASL_KEY_READ_GID
))
1394 if (out
->kselect
& PMSG_SEL_RGID
)
1400 out
->kselect
|= PMSG_SEL_RGID
;
1401 if (q
->val
[i
] != NULL
)
1403 out
->vselect
|= PMSG_SEL_RGID
;
1404 out
->rgid
= atoi(q
->val
[i
]);
1409 ksid
= string_lookup(s
, q
->key
[i
]);
1410 if (ksid
== ASL_REF_NULL
)
1416 for (j
= 0; j
< out
->kvcount
; j
+= 2)
1418 if (out
->kvlist
[j
] == ksid
)
1425 vsid
= ASL_REF_NULL
;
1426 if (q
->val
[i
] != NULL
)
1428 vsid
= string_lookup(s
, q
->val
[i
]);
1429 if (ksid
== ASL_REF_NULL
)
1436 if (out
->kvcount
== 0)
1438 out
->kvlist
= (uint64_t *)calloc(2, sizeof(uint64_t));
1442 out
->kvlist
= (uint64_t *)reallocf(out
->kvlist
, (out
->kvcount
+ 2) * sizeof(uint64_t));
1445 if (out
->kvlist
== NULL
)
1448 return ASL_STATUS_NO_MEMORY
;
1451 out
->kvlist
[out
->kvcount
++] = ksid
;
1452 out
->kvlist
[out
->kvcount
++] = vsid
;
1461 msg_match(asl_legacy1_t
*s
, uint32_t qtype
, pmsg_t
*qp
, asl_msg_t
*q
, uint32_t slot
, pmsg_t
**iopm
, asl_msg_t
**iomsg
, asl_msg_list_t
**res
, uint32_t *didmatch
)
1463 uint32_t status
, what
;
1467 if (qtype
== Q_FAIL
) return ASL_STATUS_OK
;
1469 if (qtype
== Q_NULL
)
1473 status
= pmsg_fetch(s
, slot
, PMSG_FETCH_ALL
, iopm
);
1474 if (status
!= ASL_STATUS_OK
) return status
;
1475 if (*iopm
== NULL
) return ASL_STATUS_FAILED
;
1478 else if (qtype
== Q_FAST
)
1480 if (qp
== NULL
) return ASL_STATUS_INVALID_ARG
;
1482 what
= PMSG_FETCH_STD
;
1483 if (qp
->kvcount
> 0) what
= PMSG_FETCH_ALL
;
1487 status
= pmsg_fetch(s
, slot
, what
, iopm
);
1488 if (status
!= ASL_STATUS_OK
) return status
;
1489 if (*iopm
== NULL
) return ASL_STATUS_FAILED
;
1492 status
= pmsg_match(s
, qp
, *iopm
);
1495 if ((what
== PMSG_FETCH_STD
) && ((*iopm
)->next
!= 0) && ((*iopm
)->kvcount
== 0))
1497 status
= pmsg_fetch(s
, slot
, PMSG_FETCH_KV
, iopm
);
1498 if (status
!= ASL_STATUS_OK
) return status
;
1499 if (*iopm
== NULL
) return ASL_STATUS_FAILED
;
1502 else return ASL_STATUS_OK
;
1504 else if (qtype
== Q_SLOW
)
1510 status
= pmsg_fetch(s
, slot
, PMSG_FETCH_ALL
, iopm
);
1511 if (status
!= ASL_STATUS_OK
) return status
;
1512 if (*iopm
== NULL
) return ASL_STATUS_FAILED
;
1515 status
= msg_decode(s
, *iopm
, iomsg
);
1516 if (status
== ASL_STATUS_INVALID_MESSAGE
) return ASL_STATUS_OK
;
1517 if (status
!= ASL_STATUS_OK
) return status
;
1518 if (*iomsg
== NULL
) return ASL_STATUS_FAILED
;
1522 if (asl_msg_cmp(q
, *iomsg
) != 0) status
= 1;
1523 if (status
== 0) return ASL_STATUS_OK
;
1528 if (res
== NULL
) return ASL_STATUS_OK
;
1532 status
= msg_decode(s
, *iopm
, iomsg
);
1533 if (status
== ASL_STATUS_INVALID_MESSAGE
)
1536 return ASL_STATUS_OK
;
1539 if (status
!= ASL_STATUS_OK
) return status
;
1542 if ((*res
)->count
== 0) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1543 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, (1 + (*res
)->count
) * sizeof(asl_msg_t
*));
1544 if ((*res
)->msg
== NULL
) return ASL_STATUS_NO_MEMORY
;
1546 (*res
)->msg
[(*res
)->count
++] = *iomsg
;
1548 return ASL_STATUS_OK
;
1552 next_search_slot(asl_legacy1_t
*s
, uint32_t last_si
, int32_t direction
)
1558 for (i
= last_si
+ 1; i
< s
->slotlist_count
; i
++)
1560 if (s
->slotlist
[i
].type
== DB_TYPE_MESSAGE
) return i
;
1563 return ASL_INDEX_NULL
;
1566 if (last_si
== 0) return ASL_INDEX_NULL
;
1567 if (last_si
> s
->slotlist_count
) return ASL_INDEX_NULL
;
1569 for (i
= last_si
- 1; i
> 0; i
--)
1571 if (s
->slotlist
[i
].type
== DB_TYPE_MESSAGE
) return i
;
1574 if (s
->slotlist
[0].type
== DB_TYPE_MESSAGE
) return 0;
1576 return ASL_INDEX_NULL
;
1580 query_list_to_pmsg_list(asl_legacy1_t
*s
, asl_msg_list_t
*query
, uint32_t *match
, pmsg_t
***qp
, uint32_t **qtype
, uint32_t *count
)
1583 uint32_t i
, j
, *outt
;
1589 if (query
== NULL
) return ASL_STATUS_OK
;
1590 if (match
== NULL
) return ASL_STATUS_INVALID_ARG
;
1591 if (qp
== NULL
) return ASL_STATUS_INVALID_ARG
;
1592 if (qtype
== NULL
) return ASL_STATUS_OK
;
1593 if (query
->msg
== NULL
) return ASL_STATUS_OK
;
1594 if (query
->count
== 0) return ASL_STATUS_OK
;
1596 outp
= (pmsg_t
**)calloc(query
->count
, sizeof(pmsg_t
*));
1597 if (outp
== NULL
) return ASL_STATUS_NO_MEMORY
;
1599 outt
= (uint32_t *)calloc(query
->count
, sizeof(uint32_t));
1603 return ASL_STATUS_NO_MEMORY
;
1608 for (i
= 0; i
< query
->count
; i
++)
1611 outt
[i
] = query_to_pmsg(s
, query
->msg
[i
], &pm
);
1612 if (outt
[i
] <= ASL_STATUS_FAILED
)
1614 if (pm
!= NULL
) free_pmsg(pm
);
1615 for (j
= 0; j
< i
; j
++) free_pmsg(outp
[j
]);
1618 return ASL_STATUS_NO_MEMORY
;
1624 *count
= query
->count
;
1627 return ASL_STATUS_OK
;
1631 match_worker_cleanup(pmsg_t
**ql
, uint32_t *qt
, uint32_t n
, asl_msg_list_t
**res
)
1637 for (i
= 0; i
< n
; i
++) free_pmsg(ql
[i
]);
1641 if (qt
!= NULL
) free(qt
);
1645 for (i
= 0; i
< (*res
)->count
; i
++) asl_free((*res
)->msg
[i
]);
1651 * Input to asl_legacy1_match is a list of queries.
1652 * A record in the store matches if it matches any query (i.e. query list is "OR"ed)
1654 * If counting up (direction is positive) find first record with ID > start_id.
1655 * Else if counting down (direction is negative) find first record with ID < start_id.
1657 * Set match flag on.
1658 * If any query is NULL, set match flog off (skips matching below).
1659 * Else if all queries only check "standard" keys, set std flag to on.
1661 * If a query only tests equality, convert it to a pmsg_t. The conversion routine
1662 * checks for string values that are NOT in the database. If a string is not found,
1663 * the conversion fails and the query is markes as "never matches". Otherwise,
1664 * the query is marked "fast".
1666 * If all queries are marked as "never matches", return NULL.
1669 * fetch record (with std flag)
1670 * if match flag is off, decode record and add it to result.
1671 * else for each query:
1672 * if query is NULL (shouldn't happen) decode record and add it to result. Return to match loop.
1673 * else if query never matches, ignore it.
1674 * else if query is fast, use pmsg_match. If it succeeds, decode record and add it to result. Return to match loop.
1675 * else decode record and use asl_cmp. If it succeeds, add record to result. Return to match loop.
1680 match_worker(asl_legacy1_t
*s
, asl_msg_list_t
*query
, asl_msg_list_t
**res
, uint64_t *last_id
, uint64_t **idlist
, uint32_t *idcount
, uint64_t start_id
, int32_t count
, int32_t direction
)
1682 uint32_t mx
, si
, slot
, i
, qcount
, match
, didmatch
, status
, *qtype
;
1684 pmsg_t
**qp
, *iopmsg
;
1687 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1688 if ((res
== NULL
) && (idlist
== NULL
)) return ASL_STATUS_INVALID_ARG
;
1689 if (last_id
== NULL
) return ASL_STATUS_INVALID_ARG
;
1690 if (idcount
== NULL
) return ASL_STATUS_INVALID_ARG
;
1692 if (res
!= NULL
) *res
= NULL
;
1693 if (idlist
!= NULL
) *idlist
= NULL
;
1697 if (direction
< 0) direction
= -1;
1700 si
= ASL_INDEX_NULL
;
1701 if ((direction
== -1) && (start_id
== ASL_REF_NULL
)) si
= s
->slotlist_count
;
1702 else si
= slotlist_find(s
, start_id
, direction
);
1704 si
= next_search_slot(s
, si
, direction
);
1705 if (si
== ASL_INDEX_NULL
) return ASL_STATUS_OK
;
1706 if (si
>= s
->slotlist_count
) return ASL_STATUS_FAILED
;
1708 slot
= s
->slotlist
[si
].slot
;
1710 status
= query_list_to_pmsg_list(s
, query
, &match
, &qp
, &qtype
, &qcount
);
1711 if (status
!= ASL_STATUS_OK
) return status
;
1714 * initialize result list if we've been asked to return messages
1718 *res
= (asl_msg_list_t
*)calloc(1, sizeof(asl_msg_list_t
));
1721 match_worker_cleanup(qp
, qtype
, qcount
, NULL
);
1722 return ASL_STATUS_NO_MEMORY
;
1727 * loop through records
1730 while ((count
== 0) || (*idcount
< count
))
1732 if (si
== ASL_INDEX_NULL
) break;
1733 if (si
>= s
->slotlist_count
) break;
1735 slot
= s
->slotlist
[si
].slot
;
1736 xid
= s
->slotlist
[si
].xid
;
1746 status
= msg_match(s
, Q_NULL
, NULL
, NULL
, slot
, &iopmsg
, &iomsg
, res
, &didmatch
);
1757 if (*idlist
== NULL
) *idlist
= (uint64_t *)calloc(1, sizeof(uint64_t));
1758 else *idlist
= (uint64_t *)reallocf(*idlist
, (*idcount
+ 1) * sizeof(uint64_t));
1759 if (*idlist
== NULL
) status
= ASL_STATUS_NO_MEMORY
;
1760 else (*idlist
)[*idcount
] = xid
;
1766 if (status
!= ASL_STATUS_OK
)
1768 match_worker_cleanup(qp
, qtype
, qcount
, res
);
1774 for (i
= 0; i
< qcount
; i
++)
1776 status
= msg_match(s
, qtype
[i
], qp
[i
], query
->msg
[i
], slot
, &iopmsg
, &iomsg
, res
, &didmatch
);
1777 if (status
!= ASL_STATUS_OK
)
1781 match_worker_cleanup(qp
, qtype
, qcount
, res
);
1789 if (*idlist
== NULL
) *idlist
= (uint64_t *)calloc(1, sizeof(uint64_t));
1790 else *idlist
= (uint64_t *)reallocf(*idlist
, (*idcount
+ 1) * sizeof(uint64_t));
1791 if (*idlist
== NULL
)
1793 match_worker_cleanup(qp
, qtype
, qcount
, res
);
1794 return ASL_STATUS_NO_MEMORY
;
1797 (*idlist
)[*idcount
] = xid
;
1806 if ((didmatch
== 0) || (res
== NULL
)) asl_free(iomsg
);
1809 si
= next_search_slot(s
, si
, direction
);
1812 match_worker_cleanup(qp
, qtype
, qcount
, NULL
);
1817 asl_legacy1_match(asl_legacy1_t
*s
, asl_msg_list_t
*query
, asl_msg_list_t
**res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
1822 return match_worker(s
, query
, res
, last_id
, NULL
, &idcount
, start_id
, count
, direction
);