]>
Commit | Line | Data |
---|---|---|
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_legacy1.h> | |
27 | #include <asl_private.h> | |
28 | #include <stdlib.h> | |
29 | #include <sys/file.h> | |
30 | #include <sys/stat.h> | |
31 | #include <sys/errno.h> | |
32 | #include <string.h> | |
33 | #include <membership.h> | |
34 | #include <mach/mach.h> | |
35 | #include <sys/syslimits.h> | |
36 | #include <sys/types.h> | |
37 | #include <time.h> | |
38 | #include <sys/mman.h> | |
39 | ||
40 | #define forever for(;;) | |
41 | ||
42 | #define FILE_MODE 0600 | |
43 | ||
44 | #define DB_RECORD_LEN 80 | |
45 | ||
46 | #define DB_HEADER_COOKIE_OFFSET 0 | |
47 | #define DB_HEADER_VERS_OFFSET 12 | |
48 | ||
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 | |
55 | ||
56 | /* | |
57 | * Magic Cookie for database files. | |
58 | * MAXIMUM 12 CHARS! (DB_HEADER_VERS_OFFSET) | |
59 | */ | |
60 | #define ASL_DB_COOKIE "ASL DB" | |
61 | #define ASL_DB_COOKIE_LEN 6 | |
62 | ||
63 | #define ASL_INDEX_NULL 0xffffffff | |
64 | ||
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 | |
71 | ||
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 | |
87 | ||
88 | extern time_t asl_parse_time(const char *str); | |
89 | extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); | |
90 | ||
91 | #define asl_msg_list_t asl_search_result_t | |
92 | ||
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 | |
104 | ||
105 | #define PMSG_FETCH_ALL 0 | |
106 | #define PMSG_FETCH_STD 1 | |
107 | #define PMSG_FETCH_KV 2 | |
108 | ||
109 | #define Q_NULL 100001 | |
110 | #define Q_FAST 100002 | |
111 | #define Q_SLOW 100003 | |
112 | #define Q_FAIL 100004 | |
113 | ||
114 | typedef struct | |
115 | { | |
116 | uint16_t kselect; | |
117 | uint16_t vselect; | |
118 | uint64_t msgid; | |
119 | uint64_t time; | |
120 | uint64_t host; | |
121 | uint64_t sender; | |
122 | uint64_t facility; | |
123 | uint64_t message; | |
124 | uint32_t level; | |
125 | uint32_t pid; | |
126 | int32_t uid; | |
127 | int32_t gid; | |
128 | int32_t ruid; | |
129 | int32_t rgid; | |
130 | uint32_t next; | |
131 | uint32_t kvcount; | |
132 | uint64_t *kvlist; | |
133 | } pmsg_t; | |
134 | ||
135 | static uint64_t | |
136 | _asl_htonq(uint64_t n) | |
137 | { | |
138 | #ifdef __BIG_ENDIAN__ | |
139 | return n; | |
140 | #else | |
141 | u_int32_t t; | |
142 | union | |
143 | { | |
144 | u_int64_t q; | |
145 | u_int32_t l[2]; | |
146 | } x; | |
147 | ||
148 | x.q = n; | |
149 | t = x.l[0]; | |
150 | x.l[0] = htonl(x.l[1]); | |
151 | x.l[1] = htonl(t); | |
152 | ||
153 | return x.q; | |
154 | #endif | |
155 | } | |
156 | ||
157 | static uint64_t | |
158 | _asl_ntohq(uint64_t n) | |
159 | { | |
160 | #ifdef __BIG_ENDIAN__ | |
161 | return n; | |
162 | #else | |
163 | u_int32_t t; | |
164 | union | |
165 | { | |
166 | u_int64_t q; | |
167 | u_int32_t l[2]; | |
168 | } x; | |
169 | ||
170 | x.q = n; | |
171 | t = x.l[0]; | |
172 | x.l[0] = ntohl(x.l[1]); | |
173 | x.l[1] = ntohl(t); | |
174 | ||
175 | return x.q; | |
176 | #endif | |
177 | } | |
178 | ||
179 | static uint16_t | |
180 | _asl_get_16(char *h) | |
181 | { | |
182 | uint16_t x; | |
183 | ||
184 | memcpy(&x, h, 2); | |
185 | return ntohs(x); | |
186 | } | |
187 | ||
188 | static uint32_t | |
189 | _asl_get_32(char *h) | |
190 | { | |
191 | uint32_t x; | |
192 | ||
193 | memcpy(&x, h, 4); | |
194 | return ntohl(x); | |
195 | } | |
196 | ||
197 | static uint64_t | |
198 | _asl_get_64(char *h) | |
199 | { | |
200 | uint64_t x; | |
201 | ||
202 | memcpy(&x, h, 8); | |
203 | return _asl_ntohq(x); | |
204 | } | |
205 | ||
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) | |
209 | ||
210 | /* | |
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() | |
216 | */ | |
217 | static int | |
218 | slot_comp(const void *a, const void *b) | |
219 | { | |
220 | asl_legacy1_slot_info_t *ai, *bi; | |
221 | ||
222 | if (a == NULL) | |
223 | { | |
224 | if (b == NULL) return 0; | |
225 | return -1; | |
226 | } | |
227 | ||
228 | if (b == NULL) return 1; | |
229 | ||
230 | ai = (asl_legacy1_slot_info_t *)a; | |
231 | bi = (asl_legacy1_slot_info_t *)b; | |
232 | ||
233 | if (ai->xid < bi->xid) return -1; | |
234 | ||
235 | if (ai->xid == bi->xid) | |
236 | { | |
237 | if (ai->slot < bi->slot) return -1; | |
238 | if (ai->slot == bi->slot) return 0; | |
239 | return 1; | |
240 | } | |
241 | ||
242 | return 1; | |
243 | } | |
244 | ||
245 | /* find an xid in the slot list */ | |
246 | static uint32_t | |
247 | slotlist_find(asl_legacy1_t *s, uint64_t xid, int32_t direction) | |
248 | { | |
249 | uint32_t top, bot, mid, range; | |
250 | ||
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; | |
254 | ||
255 | top = s->slotlist_count - 1; | |
256 | bot = 0; | |
257 | mid = top / 2; | |
258 | ||
259 | range = top - bot; | |
260 | while (range > 1) | |
261 | { | |
262 | if (xid == s->slotlist[mid].xid) return mid; | |
263 | else if (xid < s->slotlist[mid].xid) top = mid; | |
264 | else bot = mid; | |
265 | ||
266 | range = top - bot; | |
267 | mid = bot + (range / 2); | |
268 | } | |
269 | ||
270 | if (xid == s->slotlist[top].xid) return top; | |
271 | if (xid == s->slotlist[bot].xid) return bot; | |
272 | ||
273 | if (direction == 0) return ASL_INDEX_NULL; | |
274 | if (direction < 0) return bot; | |
275 | return top; | |
276 | } | |
277 | ||
278 | static uint32_t | |
279 | slotlist_init(asl_legacy1_t *s, uint32_t count) | |
280 | { | |
281 | uint32_t i, si, status, hash, addslot; | |
282 | uint64_t xid; | |
283 | uint8_t t; | |
284 | char tmp[DB_RECORD_LEN]; | |
285 | ||
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; | |
289 | ||
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; | |
292 | ||
293 | si = 0; | |
294 | ||
295 | for (i = 1; i < count; i++) | |
296 | { | |
297 | status = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
298 | if (status != 1) return ASL_STATUS_READ_FAILED; | |
299 | ||
300 | t = tmp[0]; | |
301 | addslot = 0; | |
302 | xid = 0; | |
303 | hash = 0; | |
304 | ||
305 | if (t == DB_TYPE_EMPTY) addslot = 1; | |
306 | ||
307 | if (t == DB_TYPE_STRING) | |
308 | { | |
309 | addslot = 1; | |
310 | xid = header_get_id(tmp); | |
311 | hash = header_get_hash(tmp); | |
312 | } | |
313 | ||
314 | if (t == DB_TYPE_MESSAGE) | |
315 | { | |
316 | addslot = 1; | |
317 | xid = header_get_id(tmp); | |
318 | } | |
319 | ||
320 | if (addslot == 1) | |
321 | { | |
322 | s->slotlist[si].type = t; | |
323 | s->slotlist[si].slot = i; | |
324 | s->slotlist[si].xid = xid; | |
325 | s->slotlist[si].hash = hash; | |
326 | si++; | |
327 | } | |
328 | } | |
329 | ||
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; | |
333 | ||
334 | /* slotlist is sorted by xid */ | |
335 | qsort((void *)s->slotlist, s->slotlist_count, sizeof(asl_legacy1_slot_info_t), slot_comp); | |
336 | ||
337 | return ASL_STATUS_OK; | |
338 | } | |
339 | ||
340 | uint32_t | |
341 | asl_legacy1_open(const char *path, asl_legacy1_t **out) | |
342 | { | |
343 | asl_legacy1_t *s; | |
344 | struct stat sb; | |
345 | int status; | |
346 | char cbuf[DB_RECORD_LEN]; | |
347 | off_t fsize; | |
348 | uint32_t count; | |
349 | ||
350 | memset(&sb, 0, sizeof(struct stat)); | |
351 | status = stat(path, &sb); | |
352 | if (status < 0) return ASL_STATUS_FAILED; | |
353 | ||
354 | fsize = sb.st_size; | |
355 | ||
356 | s = (asl_legacy1_t *)calloc(1, sizeof(asl_legacy1_t)); | |
357 | if (s == NULL) return ASL_STATUS_NO_MEMORY; | |
358 | ||
359 | s->db = fopen(path, "r"); | |
360 | if (s->db == NULL) | |
361 | { | |
362 | free(s); | |
363 | return ASL_STATUS_INVALID_STORE; | |
364 | } | |
365 | ||
366 | memset(cbuf, 0, DB_RECORD_LEN); | |
367 | status = fread(cbuf, DB_RECORD_LEN, 1, s->db); | |
368 | if (status != 1) | |
369 | { | |
370 | fclose(s->db); | |
371 | free(s); | |
372 | return ASL_STATUS_READ_FAILED; | |
373 | } | |
374 | ||
375 | /* Check the database Magic Cookie */ | |
376 | if (strncmp(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN)) | |
377 | { | |
378 | fclose(s->db); | |
379 | free(s); | |
380 | return ASL_STATUS_INVALID_STORE; | |
381 | } | |
382 | ||
383 | count = fsize / DB_RECORD_LEN; | |
384 | ||
385 | status = slotlist_init(s, count); | |
386 | ||
387 | *out = s; | |
388 | return ASL_STATUS_OK; | |
389 | } | |
390 | ||
391 | uint32_t | |
392 | asl_legacy1_close(asl_legacy1_t *s) | |
393 | { | |
394 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
395 | ||
396 | if (s->slotlist != NULL) free(s->slotlist); | |
397 | if (s->db != NULL) fclose(s->db); | |
398 | free(s); | |
399 | ||
400 | return ASL_STATUS_OK; | |
401 | } | |
402 | ||
403 | static uint32_t | |
404 | string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out) | |
405 | { | |
406 | off_t offset; | |
407 | uint8_t type; | |
408 | uint32_t status, next, len, x, remaining; | |
409 | char *outstr, *p, tmp[DB_RECORD_LEN]; | |
410 | ||
411 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
412 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
413 | ||
414 | *out = NULL; | |
415 | offset = slot * DB_RECORD_LEN; | |
416 | status = fseek(s->db, offset, SEEK_SET); | |
417 | ||
418 | if (status < 0) return ASL_STATUS_READ_FAILED; | |
419 | ||
420 | status = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
421 | if (status != 1) return ASL_STATUS_READ_FAILED; | |
422 | ||
423 | type = tmp[0]; | |
424 | if (type != DB_TYPE_STRING) return ASL_STATUS_INVALID_STRING; | |
425 | ||
426 | len = _asl_get_32(tmp + 21); | |
427 | if (len == 0) return ASL_STATUS_OK; | |
428 | ||
429 | next = header_get_next(tmp); | |
430 | ||
431 | outstr = calloc(1, len); | |
432 | if (outstr == NULL) return ASL_STATUS_NO_MEMORY; | |
433 | ||
434 | p = outstr; | |
435 | remaining = len; | |
436 | ||
437 | x = DB_RECORD_LEN - DB_HLEN_STRING; | |
438 | if (x > remaining) x = remaining; | |
439 | ||
440 | memcpy(p, tmp + DB_HLEN_STRING, x); | |
441 | p += x; | |
442 | remaining -= x; | |
443 | ||
444 | while ((next != 0) && (remaining > 0)) | |
445 | { | |
446 | offset = next * DB_RECORD_LEN; | |
447 | status = fseek(s->db, offset, SEEK_SET); | |
448 | ||
449 | if (status < 0) | |
450 | { | |
451 | free(outstr); | |
452 | return ASL_STATUS_READ_FAILED; | |
453 | } | |
454 | ||
455 | status = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
456 | if (status != 1) | |
457 | { | |
458 | free(outstr); | |
459 | return ASL_STATUS_READ_FAILED; | |
460 | } | |
461 | ||
462 | next = header_get_next(tmp); | |
463 | ||
464 | x = DB_RECORD_LEN - DB_HLEN_STRCONT; | |
465 | if (x > remaining) x = remaining; | |
466 | ||
467 | memcpy(p, tmp + DB_HLEN_STRCONT, x); | |
468 | p += x; | |
469 | remaining -= x; | |
470 | } | |
471 | ||
472 | if ((next != 0) || (remaining != 0)) | |
473 | { | |
474 | free(outstr); | |
475 | return ASL_STATUS_READ_FAILED; | |
476 | } | |
477 | ||
478 | *out = outstr; | |
479 | return ASL_STATUS_OK; | |
480 | } | |
481 | ||
482 | static uint32_t | |
483 | string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out) | |
484 | { | |
485 | uint32_t i, len, ref; | |
486 | uint64_t nsid; | |
487 | uint8_t inls; | |
488 | char *p; | |
489 | ||
490 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
491 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
492 | ||
493 | *out = NULL; | |
494 | if (sid == ASL_REF_NULL) return ASL_STATUS_OK; | |
495 | ||
496 | ref = 0; | |
497 | ||
498 | inls = 0; | |
499 | nsid = _asl_htonq(sid); | |
500 | memcpy(&inls, &nsid, 1); | |
501 | if (inls & 0x80) | |
502 | { | |
503 | /* inline string */ | |
504 | inls &= 0x0f; | |
505 | len = inls; | |
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; | |
511 | } | |
512 | ||
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; | |
516 | ||
517 | return string_fetch_slot(s, s->slotlist[i].slot, out); | |
518 | } | |
519 | ||
520 | static uint32_t | |
521 | pmsg_fetch(asl_legacy1_t *s, uint32_t slot, uint32_t action, pmsg_t **pmsg) | |
522 | { | |
523 | off_t offset; | |
524 | uint32_t status, i, n, v32, next; | |
525 | int32_t msgu, msgg; | |
526 | uint64_t msgid; | |
527 | uint16_t flags; | |
528 | pmsg_t *out; | |
529 | char *p, tmp[DB_RECORD_LEN]; | |
530 | ||
531 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
532 | if (pmsg == NULL) return ASL_STATUS_INVALID_ARG; | |
533 | ||
534 | out = NULL; | |
535 | ||
536 | if ((action == PMSG_FETCH_ALL) || (action == PMSG_FETCH_STD)) | |
537 | { | |
538 | *pmsg = NULL; | |
539 | ||
540 | offset = slot * DB_RECORD_LEN; | |
541 | status = fseek(s->db, offset, SEEK_SET); | |
542 | ||
543 | if (status < 0) return ASL_STATUS_READ_FAILED; | |
544 | ||
545 | status = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
546 | if (status != 1) return ASL_STATUS_READ_FAILED; | |
547 | ||
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); | |
552 | ||
553 | out = (pmsg_t *)calloc(1, sizeof(pmsg_t)); | |
554 | if (out == NULL) return ASL_STATUS_NO_MEMORY; | |
555 | ||
556 | ||
557 | p = tmp + 21; | |
558 | ||
559 | /* ID */ | |
560 | out->msgid = msgid; | |
561 | ||
562 | /* ReadUID */ | |
563 | out->ruid = msgu; | |
564 | ||
565 | /* ReadGID */ | |
566 | out->rgid = msgg; | |
567 | ||
568 | /* Time */ | |
569 | out->time = _asl_get_64(p); | |
570 | p += 8; | |
571 | ||
572 | /* Host */ | |
573 | out->host = _asl_get_64(p); | |
574 | p += 8; | |
575 | ||
576 | /* Sender */ | |
577 | out->sender = _asl_get_64(p); | |
578 | p += 8; | |
579 | ||
580 | /* Facility */ | |
581 | out->facility = _asl_get_64(p); | |
582 | p += 8; | |
583 | ||
584 | /* Level */ | |
585 | out->level = _asl_get_32(p); | |
586 | p += 4; | |
587 | ||
588 | /* PID */ | |
589 | out->pid = _asl_get_32(p); | |
590 | p += 4; | |
591 | ||
592 | /* UID */ | |
593 | out->uid = _asl_get_32(p); | |
594 | p += 4; | |
595 | ||
596 | /* GID */ | |
597 | out->gid = _asl_get_32(p); | |
598 | p += 4; | |
599 | ||
600 | /* Message */ | |
601 | out->message = _asl_get_64(p); | |
602 | p += 8; | |
603 | ||
604 | next = header_get_next(tmp); | |
605 | out->next = next; | |
606 | ||
607 | if (action == PMSG_FETCH_STD) | |
608 | { | |
609 | /* caller only wants "standard" keys */ | |
610 | *pmsg = out; | |
611 | return ASL_STATUS_OK; | |
612 | } | |
613 | ||
614 | *pmsg = out; | |
615 | } | |
616 | else | |
617 | { | |
618 | out = *pmsg; | |
619 | } | |
620 | ||
621 | n = 0; | |
622 | next = out->next; | |
623 | ||
624 | while (next != 0) | |
625 | { | |
626 | offset = next * DB_RECORD_LEN; | |
627 | status = fseek(s->db, offset, SEEK_SET); | |
628 | if (status < 0) | |
629 | { | |
630 | *pmsg = NULL; | |
631 | free(out); | |
632 | return ASL_STATUS_READ_FAILED; | |
633 | } | |
634 | ||
635 | status = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
636 | if (status != 1) | |
637 | { | |
638 | *pmsg = NULL; | |
639 | free(out); | |
640 | return ASL_STATUS_READ_FAILED; | |
641 | } | |
642 | ||
643 | if (out->kvcount == 0) | |
644 | { | |
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) | |
649 | { | |
650 | *pmsg = NULL; | |
651 | free(out); | |
652 | return ASL_STATUS_NO_MEMORY; | |
653 | } | |
654 | } | |
655 | ||
656 | p = tmp + 9; | |
657 | ||
658 | for (i = 0; (i < 4) && (n < out->kvcount); i++) | |
659 | { | |
660 | out->kvlist[n++] = _asl_get_64(p); | |
661 | p += 8; | |
662 | ||
663 | out->kvlist[n++] = _asl_get_64(p); | |
664 | p += 8; | |
665 | } | |
666 | ||
667 | next = header_get_next(tmp); | |
668 | } | |
669 | ||
670 | return ASL_STATUS_OK; | |
671 | } | |
672 | ||
673 | static uint32_t | |
674 | pmsg_match(asl_legacy1_t *s, pmsg_t *q, pmsg_t *m) | |
675 | { | |
676 | uint32_t i, j; | |
677 | ||
678 | if (s == NULL) return 0; | |
679 | if (q == NULL) return 1; | |
680 | if (m == NULL) return 0; | |
681 | ||
682 | if (q->kselect & PMSG_SEL_TIME) | |
683 | { | |
684 | if (q->time == ASL_REF_NULL) return 0; | |
685 | if ((q->vselect & PMSG_SEL_TIME) && (q->time != m->time)) return 0; | |
686 | } | |
687 | ||
688 | if (q->kselect & PMSG_SEL_HOST) | |
689 | { | |
690 | if (q->host == ASL_REF_NULL) return 0; | |
691 | if ((q->vselect & PMSG_SEL_HOST) && (q->host != m->host)) return 0; | |
692 | } | |
693 | ||
694 | if (q->kselect & PMSG_SEL_SENDER) | |
695 | { | |
696 | if (q->sender == ASL_REF_NULL) return 0; | |
697 | if ((q->vselect & PMSG_SEL_SENDER) && (q->sender != m->sender)) return 0; | |
698 | } | |
699 | ||
700 | if (q->kselect & PMSG_SEL_FACILITY) | |
701 | { | |
702 | if (q->facility == ASL_REF_NULL) return 0; | |
703 | if ((q->vselect & PMSG_SEL_FACILITY) && (q->facility != m->facility)) return 0; | |
704 | } | |
705 | ||
706 | if (q->kselect & PMSG_SEL_MESSAGE) | |
707 | { | |
708 | if (q->message == ASL_REF_NULL) return 0; | |
709 | if ((q->vselect & PMSG_SEL_MESSAGE) && (q->message != m->message)) return 0; | |
710 | } | |
711 | ||
712 | if (q->kselect & PMSG_SEL_LEVEL) | |
713 | { | |
714 | if (q->level == ASL_INDEX_NULL) return 0; | |
715 | if ((q->vselect & PMSG_SEL_LEVEL) && (q->level != m->level)) return 0; | |
716 | } | |
717 | ||
718 | if (q->kselect & PMSG_SEL_PID) | |
719 | { | |
720 | if (q->pid == -1) return 0; | |
721 | if ((q->vselect & PMSG_SEL_PID) && (q->pid != m->pid)) return 0; | |
722 | } | |
723 | ||
724 | if (q->kselect & PMSG_SEL_UID) | |
725 | { | |
726 | if (q->uid == -2) return 0; | |
727 | if ((q->vselect & PMSG_SEL_UID) && (q->uid != m->uid)) return 0; | |
728 | } | |
729 | ||
730 | if (q->kselect & PMSG_SEL_GID) | |
731 | { | |
732 | if (q->gid == -2) return 0; | |
733 | if ((q->vselect & PMSG_SEL_GID) && (q->gid != m->gid)) return 0; | |
734 | } | |
735 | ||
736 | if (q->kselect & PMSG_SEL_RUID) | |
737 | { | |
738 | if (q->ruid == -1) return 0; | |
739 | if ((q->vselect & PMSG_SEL_RUID) && (q->ruid != m->ruid)) return 0; | |
740 | } | |
741 | ||
742 | if (q->kselect & PMSG_SEL_RGID) | |
743 | { | |
744 | if (q->rgid == -1) return 0; | |
745 | if ((q->vselect & PMSG_SEL_RGID) && (q->rgid != m->rgid)) return 0; | |
746 | } | |
747 | ||
748 | for (i = 0; i < q->kvcount; i += 2) | |
749 | { | |
750 | for (j = 0; j < m->kvcount; j += 2) | |
751 | { | |
752 | if (q->kvlist[i] == m->kvlist[j]) | |
753 | { | |
754 | if (q->kvlist[i + 1] == m->kvlist[j + 1]) break; | |
755 | return 0; | |
756 | } | |
757 | } | |
758 | ||
759 | if (j >= m->kvcount) return 0; | |
760 | } | |
761 | ||
762 | return 1; | |
763 | } | |
764 | ||
765 | static void | |
766 | free_pmsg(pmsg_t *p) | |
767 | { | |
768 | if (p == NULL) return; | |
769 | if (p->kvlist != NULL) free(p->kvlist); | |
770 | free(p); | |
771 | } | |
772 | ||
773 | static uint32_t | |
774 | pmsg_fetch_by_id(asl_legacy1_t *s, uint64_t msgid, pmsg_t **pmsg, uint32_t *slot) | |
775 | { | |
776 | uint32_t i, status; | |
777 | ||
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; | |
781 | ||
782 | *slot = ASL_INDEX_NULL; | |
783 | ||
784 | i = slotlist_find(s, msgid, 0); | |
785 | if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID; | |
786 | ||
787 | *slot = s->slotlist[i].slot; | |
788 | ||
789 | /* read the message */ | |
790 | *pmsg = NULL; | |
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; | |
794 | ||
795 | return status; | |
796 | } | |
797 | ||
798 | static uint32_t | |
799 | msg_decode(asl_legacy1_t *s, pmsg_t *pmsg, asl_msg_t **out) | |
800 | { | |
801 | uint32_t status, i, n; | |
802 | char *key, *val; | |
803 | asl_msg_t *msg; | |
804 | ||
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; | |
808 | ||
809 | *out = NULL; | |
810 | ||
811 | msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); | |
812 | if (msg == NULL) return ASL_STATUS_NO_MEMORY; | |
813 | ||
814 | msg->type = ASL_TYPE_MSG; | |
815 | msg->count = 0; | |
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++; | |
827 | ||
828 | msg->count += pmsg->kvcount / 2; | |
829 | ||
830 | if (msg->count == 0) | |
831 | { | |
832 | free(msg); | |
833 | return ASL_STATUS_INVALID_MESSAGE; | |
834 | } | |
835 | ||
836 | /* Message ID */ | |
837 | msg->count += 1; | |
838 | ||
839 | msg->key = (char **)calloc(msg->count, sizeof(char *)); | |
840 | if (msg->key == NULL) | |
841 | { | |
842 | free(msg); | |
843 | return ASL_STATUS_NO_MEMORY; | |
844 | } | |
845 | ||
846 | msg->val = (char **)calloc(msg->count, sizeof(char *)); | |
847 | if (msg->val == NULL) | |
848 | { | |
849 | free(msg->key); | |
850 | free(msg); | |
851 | return ASL_STATUS_NO_MEMORY; | |
852 | } | |
853 | ||
854 | n = 0; | |
855 | ||
856 | /* Time */ | |
857 | if (pmsg->time != ASL_REF_NULL) | |
858 | { | |
859 | msg->key[n] = strdup(ASL_KEY_TIME); | |
860 | if (msg->key[n] == NULL) | |
861 | { | |
862 | asl_free(msg); | |
863 | return ASL_STATUS_NO_MEMORY; | |
864 | } | |
865 | ||
866 | asprintf(&(msg->val[n]), "%llu", pmsg->time); | |
867 | if (msg->val[n] == NULL) | |
868 | { | |
869 | asl_free(msg); | |
870 | return ASL_STATUS_NO_MEMORY; | |
871 | } | |
872 | n++; | |
873 | } | |
874 | ||
875 | /* Host */ | |
876 | if (pmsg->host != ASL_REF_NULL) | |
877 | { | |
878 | msg->key[n] = strdup(ASL_KEY_HOST); | |
879 | if (msg->key[n] == NULL) | |
880 | { | |
881 | asl_free(msg); | |
882 | return ASL_STATUS_NO_MEMORY; | |
883 | } | |
884 | ||
885 | status = string_fetch_sid(s, pmsg->host, &(msg->val[n])); | |
886 | n++; | |
887 | } | |
888 | ||
889 | /* Sender */ | |
890 | if (pmsg->sender != ASL_REF_NULL) | |
891 | { | |
892 | msg->key[n] = strdup(ASL_KEY_SENDER); | |
893 | if (msg->key[n] == NULL) | |
894 | { | |
895 | asl_free(msg); | |
896 | return ASL_STATUS_NO_MEMORY; | |
897 | } | |
898 | ||
899 | status = string_fetch_sid(s, pmsg->sender, &(msg->val[n])); | |
900 | n++; | |
901 | } | |
902 | ||
903 | /* Facility */ | |
904 | if (pmsg->facility != ASL_REF_NULL) | |
905 | { | |
906 | msg->key[n] = strdup(ASL_KEY_FACILITY); | |
907 | if (msg->key[n] == NULL) | |
908 | { | |
909 | asl_free(msg); | |
910 | return ASL_STATUS_NO_MEMORY; | |
911 | } | |
912 | ||
913 | status = string_fetch_sid(s, pmsg->facility, &(msg->val[n])); | |
914 | n++; | |
915 | } | |
916 | ||
917 | /* Level */ | |
918 | if (pmsg->level != ASL_INDEX_NULL) | |
919 | { | |
920 | msg->key[n] = strdup(ASL_KEY_LEVEL); | |
921 | if (msg->key[n] == NULL) | |
922 | { | |
923 | asl_free(msg); | |
924 | return ASL_STATUS_NO_MEMORY; | |
925 | } | |
926 | ||
927 | asprintf(&(msg->val[n]), "%u", pmsg->level); | |
928 | if (msg->val[n] == NULL) | |
929 | { | |
930 | asl_free(msg); | |
931 | return ASL_STATUS_NO_MEMORY; | |
932 | } | |
933 | n++; | |
934 | } | |
935 | ||
936 | /* PID */ | |
937 | if (pmsg->pid != -1) | |
938 | { | |
939 | msg->key[n] = strdup(ASL_KEY_PID); | |
940 | if (msg->key[n] == NULL) | |
941 | { | |
942 | asl_free(msg); | |
943 | return ASL_STATUS_NO_MEMORY; | |
944 | } | |
945 | ||
946 | asprintf(&(msg->val[n]), "%d", pmsg->pid); | |
947 | if (msg->val[n] == NULL) | |
948 | { | |
949 | asl_free(msg); | |
950 | return ASL_STATUS_NO_MEMORY; | |
951 | } | |
952 | n++; | |
953 | } | |
954 | ||
955 | /* UID */ | |
956 | if (pmsg->uid != -2) | |
957 | { | |
958 | msg->key[n] = strdup(ASL_KEY_UID); | |
959 | if (msg->key[n] == NULL) | |
960 | { | |
961 | asl_free(msg); | |
962 | return ASL_STATUS_NO_MEMORY; | |
963 | } | |
964 | ||
965 | asprintf(&(msg->val[n]), "%d", pmsg->uid); | |
966 | if (msg->val[n] == NULL) | |
967 | { | |
968 | asl_free(msg); | |
969 | return ASL_STATUS_NO_MEMORY; | |
970 | } | |
971 | n++; | |
972 | } | |
973 | ||
974 | /* GID */ | |
975 | if (pmsg->gid != -2) | |
976 | { | |
977 | msg->key[n] = strdup(ASL_KEY_GID); | |
978 | if (msg->key[n] == NULL) | |
979 | { | |
980 | asl_free(msg); | |
981 | return ASL_STATUS_NO_MEMORY; | |
982 | } | |
983 | ||
984 | asprintf(&(msg->val[n]), "%d", pmsg->gid); | |
985 | if (msg->val[n] == NULL) | |
986 | { | |
987 | asl_free(msg); | |
988 | return ASL_STATUS_NO_MEMORY; | |
989 | } | |
990 | n++; | |
991 | } | |
992 | ||
993 | /* Message */ | |
994 | if (pmsg->message != ASL_REF_NULL) | |
995 | { | |
996 | msg->key[n] = strdup(ASL_KEY_MSG); | |
997 | if (msg->key[n] == NULL) | |
998 | { | |
999 | asl_free(msg); | |
1000 | return ASL_STATUS_NO_MEMORY; | |
1001 | } | |
1002 | ||
1003 | status = string_fetch_sid(s, pmsg->message, &(msg->val[n])); | |
1004 | n++; | |
1005 | } | |
1006 | ||
1007 | /* ReadUID */ | |
1008 | if (pmsg->ruid != -1) | |
1009 | { | |
1010 | msg->key[n] = strdup(ASL_KEY_READ_UID); | |
1011 | if (msg->key[n] == NULL) | |
1012 | { | |
1013 | asl_free(msg); | |
1014 | return ASL_STATUS_NO_MEMORY; | |
1015 | } | |
1016 | ||
1017 | asprintf(&(msg->val[n]), "%d", pmsg->ruid); | |
1018 | if (msg->val[n] == NULL) | |
1019 | { | |
1020 | asl_free(msg); | |
1021 | return ASL_STATUS_NO_MEMORY; | |
1022 | } | |
1023 | n++; | |
1024 | } | |
1025 | ||
1026 | /* ReadGID */ | |
1027 | if (pmsg->rgid != -1) | |
1028 | { | |
1029 | msg->key[n] = strdup(ASL_KEY_READ_GID); | |
1030 | if (msg->key[n] == NULL) | |
1031 | { | |
1032 | asl_free(msg); | |
1033 | return ASL_STATUS_NO_MEMORY; | |
1034 | } | |
1035 | ||
1036 | asprintf(&(msg->val[n]), "%d", pmsg->rgid); | |
1037 | if (msg->val[n] == NULL) | |
1038 | { | |
1039 | asl_free(msg); | |
1040 | return ASL_STATUS_NO_MEMORY; | |
1041 | } | |
1042 | n++; | |
1043 | } | |
1044 | ||
1045 | /* Message ID */ | |
1046 | msg->key[n] = strdup(ASL_KEY_MSG_ID); | |
1047 | if (msg->key[n] == NULL) | |
1048 | { | |
1049 | asl_free(msg); | |
1050 | return ASL_STATUS_NO_MEMORY; | |
1051 | } | |
1052 | ||
1053 | asprintf(&(msg->val[n]), "%llu", pmsg->msgid); | |
1054 | if (msg->val[n] == NULL) | |
1055 | { | |
1056 | asl_free(msg); | |
1057 | return ASL_STATUS_NO_MEMORY; | |
1058 | } | |
1059 | n++; | |
1060 | ||
1061 | /* Key - Value List */ | |
1062 | for (i = 0; i < pmsg->kvcount; i++) | |
1063 | { | |
1064 | key = NULL; | |
1065 | status = string_fetch_sid(s, pmsg->kvlist[i++], &key); | |
1066 | if (status != ASL_STATUS_OK) | |
1067 | { | |
1068 | if (key != NULL) free(key); | |
1069 | continue; | |
1070 | } | |
1071 | ||
1072 | val = NULL; | |
1073 | status = string_fetch_sid(s, pmsg->kvlist[i], &val); | |
1074 | if (status != ASL_STATUS_OK) | |
1075 | { | |
1076 | if (key != NULL) free(key); | |
1077 | if (val != NULL) free(val); | |
1078 | continue; | |
1079 | } | |
1080 | ||
1081 | msg->key[n] = key; | |
1082 | msg->val[n] = val; | |
1083 | n++; | |
1084 | } | |
1085 | ||
1086 | *out = msg; | |
1087 | return ASL_STATUS_OK; | |
1088 | } | |
1089 | ||
1090 | /* | |
1091 | * Finds string either in the string cache or in the database | |
1092 | */ | |
1093 | static uint32_t | |
1094 | store_string_find(asl_legacy1_t *s, uint32_t hash, const char *str, uint32_t *index) | |
1095 | { | |
1096 | uint32_t i, status; | |
1097 | char *tmp; | |
1098 | ||
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; | |
1103 | ||
1104 | /* check the database */ | |
1105 | for (i = 0; i < s->slotlist_count; i++) | |
1106 | { | |
1107 | if ((s->slotlist[i].type != DB_TYPE_STRING) || (s->slotlist[i].hash != hash)) continue; | |
1108 | ||
1109 | /* read the whole string */ | |
1110 | tmp = NULL; | |
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; | |
1114 | ||
1115 | status = strcmp(tmp, str); | |
1116 | free(tmp); | |
1117 | if (status != 0) continue; | |
1118 | ||
1119 | /* Bingo! */ | |
1120 | *index = i; | |
1121 | return ASL_STATUS_OK; | |
1122 | } | |
1123 | ||
1124 | return ASL_STATUS_FAILED; | |
1125 | } | |
1126 | ||
1127 | /* | |
1128 | * Looks up a string ID number. | |
1129 | */ | |
1130 | static uint64_t | |
1131 | string_lookup(asl_legacy1_t *s, const char *str) | |
1132 | { | |
1133 | uint32_t status, hash, index, slot, len; | |
1134 | uint64_t nsid, sid; | |
1135 | char *p; | |
1136 | uint8_t inls; | |
1137 | ||
1138 | if (s == NULL) return ASL_REF_NULL; | |
1139 | if (str == NULL) return ASL_REF_NULL; | |
1140 | ||
1141 | sid = ASL_REF_NULL; | |
1142 | index = ASL_INDEX_NULL; | |
1143 | slot = ASL_INDEX_NULL; | |
1144 | ||
1145 | len = strlen(str); | |
1146 | if (len < 8) | |
1147 | { | |
1148 | /* inline string */ | |
1149 | inls = len; | |
1150 | inls |= 0x80; | |
1151 | ||
1152 | nsid = 0; | |
1153 | p = (char *)&nsid; | |
1154 | memcpy(p, &inls, 1); | |
1155 | memcpy(p + 1, str, len); | |
1156 | sid = _asl_ntohq(nsid); | |
1157 | return sid; | |
1158 | } | |
1159 | ||
1160 | hash = asl_core_string_hash(str, len); | |
1161 | ||
1162 | /* check the database */ | |
1163 | status = store_string_find(s, hash, str, &index); | |
1164 | if (status == ASL_STATUS_OK) | |
1165 | { | |
1166 | if (index == ASL_INDEX_NULL) return ASL_REF_NULL; | |
1167 | return s->slotlist[index].xid; | |
1168 | } | |
1169 | ||
1170 | return ASL_REF_NULL; | |
1171 | } | |
1172 | ||
1173 | uint32_t | |
1174 | asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, asl_msg_t **msg) | |
1175 | { | |
1176 | uint32_t status, slot; | |
1177 | pmsg_t *pmsg; | |
1178 | ||
1179 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
1180 | if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG; | |
1181 | ||
1182 | pmsg = NULL; | |
1183 | slot = ASL_INDEX_NULL; | |
1184 | ||
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; | |
1188 | ||
1189 | status = msg_decode(s, pmsg, msg); | |
1190 | free_pmsg(pmsg); | |
1191 | ||
1192 | return status; | |
1193 | } | |
1194 | ||
1195 | static uint32_t | |
1196 | query_to_pmsg(asl_legacy1_t *s, asl_msg_t *q, pmsg_t **p) | |
1197 | { | |
1198 | pmsg_t *out; | |
1199 | uint32_t i, j; | |
1200 | uint64_t ksid, vsid; | |
1201 | ||
1202 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
1203 | if (p == NULL) return ASL_STATUS_INVALID_ARG; | |
1204 | ||
1205 | if (q == NULL) return Q_NULL; | |
1206 | if (q->count == 0) return Q_NULL; | |
1207 | ||
1208 | *p = NULL; | |
1209 | ||
1210 | if (q->op != NULL) | |
1211 | { | |
1212 | for (i = 0; i < q->count; i++) if (q->op[i] != ASL_QUERY_OP_EQUAL) return Q_SLOW; | |
1213 | } | |
1214 | ||
1215 | out = (pmsg_t *)calloc(1, sizeof(pmsg_t)); | |
1216 | if (out == NULL) return ASL_STATUS_NO_MEMORY; | |
1217 | ||
1218 | for (i = 0; i < q->count; i++) | |
1219 | { | |
1220 | if (q->key[i] == NULL) continue; | |
1221 | ||
1222 | else if (!strcmp(q->key[i], ASL_KEY_TIME)) | |
1223 | { | |
1224 | if (out->kselect & PMSG_SEL_TIME) | |
1225 | { | |
1226 | free_pmsg(out); | |
1227 | return Q_SLOW; | |
1228 | } | |
1229 | ||
1230 | out->kselect |= PMSG_SEL_TIME; | |
1231 | if (q->val[i] != NULL) | |
1232 | { | |
1233 | out->vselect |= PMSG_SEL_TIME; | |
1234 | out->time = asl_parse_time(q->val[i]); | |
1235 | } | |
1236 | } | |
1237 | else if (!strcmp(q->key[i], ASL_KEY_HOST)) | |
1238 | { | |
1239 | if (out->kselect & PMSG_SEL_HOST) | |
1240 | { | |
1241 | free_pmsg(out); | |
1242 | return Q_SLOW; | |
1243 | } | |
1244 | ||
1245 | out->kselect |= PMSG_SEL_HOST; | |
1246 | if (q->val[i] != NULL) | |
1247 | { | |
1248 | out->vselect |= PMSG_SEL_HOST; | |
1249 | out->host = string_lookup(s, q->val[i]); | |
1250 | if (out->host == ASL_REF_NULL) | |
1251 | { | |
1252 | free_pmsg(out); | |
1253 | return Q_FAIL; | |
1254 | } | |
1255 | } | |
1256 | } | |
1257 | else if (!strcmp(q->key[i], ASL_KEY_SENDER)) | |
1258 | { | |
1259 | if (out->kselect & PMSG_SEL_SENDER) | |
1260 | { | |
1261 | free_pmsg(out); | |
1262 | return Q_SLOW; | |
1263 | } | |
1264 | ||
1265 | out->kselect |= PMSG_SEL_SENDER; | |
1266 | if (q->val[i] != NULL) | |
1267 | { | |
1268 | out->vselect |= PMSG_SEL_SENDER; | |
1269 | out->sender = string_lookup(s, q->val[i]); | |
1270 | if (out->sender == ASL_REF_NULL) | |
1271 | { | |
1272 | free_pmsg(out); | |
1273 | return Q_FAIL; | |
1274 | } | |
1275 | } | |
1276 | } | |
1277 | else if (!strcmp(q->key[i], ASL_KEY_PID)) | |
1278 | { | |
1279 | if (out->kselect & PMSG_SEL_PID) | |
1280 | { | |
1281 | free_pmsg(out); | |
1282 | return Q_SLOW; | |
1283 | } | |
1284 | ||
1285 | out->kselect |= PMSG_SEL_PID; | |
1286 | if (q->val[i] != NULL) | |
1287 | { | |
1288 | out->vselect |= PMSG_SEL_PID; | |
1289 | out->pid = atoi(q->val[i]); | |
1290 | } | |
1291 | } | |
1292 | else if (!strcmp(q->key[i], ASL_KEY_UID)) | |
1293 | { | |
1294 | if (out->kselect & PMSG_SEL_UID) | |
1295 | { | |
1296 | free_pmsg(out); | |
1297 | return Q_SLOW; | |
1298 | } | |
1299 | ||
1300 | out->kselect |= PMSG_SEL_UID; | |
1301 | if (q->val[i] != NULL) | |
1302 | { | |
1303 | out->vselect |= PMSG_SEL_UID; | |
1304 | out->uid = atoi(q->val[i]); | |
1305 | } | |
1306 | } | |
1307 | else if (!strcmp(q->key[i], ASL_KEY_GID)) | |
1308 | { | |
1309 | if (out->kselect & PMSG_SEL_GID) | |
1310 | { | |
1311 | free_pmsg(out); | |
1312 | return Q_SLOW; | |
1313 | } | |
1314 | ||
1315 | out->kselect |= PMSG_SEL_GID; | |
1316 | if (q->val[i] != NULL) | |
1317 | { | |
1318 | out->vselect |= PMSG_SEL_GID; | |
1319 | out->gid = atoi(q->val[i]); | |
1320 | } | |
1321 | } | |
1322 | else if (!strcmp(q->key[i], ASL_KEY_LEVEL)) | |
1323 | { | |
1324 | if (out->kselect & PMSG_SEL_LEVEL) | |
1325 | { | |
1326 | free_pmsg(out); | |
1327 | return Q_SLOW; | |
1328 | } | |
1329 | ||
1330 | out->kselect |= PMSG_SEL_LEVEL; | |
1331 | if (q->val[i] != NULL) | |
1332 | { | |
1333 | out->vselect |= PMSG_SEL_LEVEL; | |
1334 | out->level = atoi(q->val[i]); | |
1335 | } | |
1336 | } | |
1337 | else if (!strcmp(q->key[i], ASL_KEY_MSG)) | |
1338 | { | |
1339 | if (out->kselect & PMSG_SEL_MESSAGE) | |
1340 | { | |
1341 | free_pmsg(out); | |
1342 | return Q_SLOW; | |
1343 | } | |
1344 | ||
1345 | out->kselect |= PMSG_SEL_MESSAGE; | |
1346 | if (q->val[i] != NULL) | |
1347 | { | |
1348 | out->vselect |= PMSG_SEL_MESSAGE; | |
1349 | out->message = string_lookup(s, q->val[i]); | |
1350 | if (out->message == ASL_REF_NULL) | |
1351 | { | |
1352 | free_pmsg(out); | |
1353 | return Q_FAIL; | |
1354 | } | |
1355 | } | |
1356 | } | |
1357 | else if (!strcmp(q->key[i], ASL_KEY_FACILITY)) | |
1358 | { | |
1359 | if (out->kselect & PMSG_SEL_FACILITY) | |
1360 | { | |
1361 | free_pmsg(out); | |
1362 | return Q_SLOW; | |
1363 | } | |
1364 | ||
1365 | out->kselect |= PMSG_SEL_FACILITY; | |
1366 | if (q->val[i] != NULL) | |
1367 | { | |
1368 | out->vselect |= PMSG_SEL_FACILITY; | |
1369 | out->facility = string_lookup(s, q->val[i]); | |
1370 | if (out->facility == ASL_REF_NULL) | |
1371 | { | |
1372 | free_pmsg(out); | |
1373 | return Q_FAIL; | |
1374 | } | |
1375 | } | |
1376 | } | |
1377 | else if (!strcmp(q->key[i], ASL_KEY_READ_UID)) | |
1378 | { | |
1379 | if (out->kselect & PMSG_SEL_RUID) | |
1380 | { | |
1381 | free_pmsg(out); | |
1382 | return Q_SLOW; | |
1383 | } | |
1384 | ||
1385 | out->kselect |= PMSG_SEL_RUID; | |
1386 | if (q->val[i] != NULL) | |
1387 | { | |
1388 | out->vselect |= PMSG_SEL_RUID; | |
1389 | out->ruid = atoi(q->val[i]); | |
1390 | } | |
1391 | } | |
1392 | else if (!strcmp(q->key[i], ASL_KEY_READ_GID)) | |
1393 | { | |
1394 | if (out->kselect & PMSG_SEL_RGID) | |
1395 | { | |
1396 | free_pmsg(out); | |
1397 | return Q_SLOW; | |
1398 | } | |
1399 | ||
1400 | out->kselect |= PMSG_SEL_RGID; | |
1401 | if (q->val[i] != NULL) | |
1402 | { | |
1403 | out->vselect |= PMSG_SEL_RGID; | |
1404 | out->rgid = atoi(q->val[i]); | |
1405 | } | |
1406 | } | |
1407 | else | |
1408 | { | |
1409 | ksid = string_lookup(s, q->key[i]); | |
1410 | if (ksid == ASL_REF_NULL) | |
1411 | { | |
1412 | free_pmsg(out); | |
1413 | return Q_FAIL; | |
1414 | } | |
1415 | ||
1416 | for (j = 0; j < out->kvcount; j += 2) | |
1417 | { | |
1418 | if (out->kvlist[j] == ksid) | |
1419 | { | |
1420 | free_pmsg(out); | |
1421 | return Q_SLOW; | |
1422 | } | |
1423 | } | |
1424 | ||
1425 | vsid = ASL_REF_NULL; | |
1426 | if (q->val[i] != NULL) | |
1427 | { | |
1428 | vsid = string_lookup(s, q->val[i]); | |
1429 | if (ksid == ASL_REF_NULL) | |
1430 | { | |
1431 | free_pmsg(out); | |
1432 | return Q_FAIL; | |
1433 | } | |
1434 | } | |
1435 | ||
1436 | if (out->kvcount == 0) | |
1437 | { | |
1438 | out->kvlist = (uint64_t *)calloc(2, sizeof(uint64_t)); | |
1439 | } | |
1440 | else | |
1441 | { | |
1442 | out->kvlist = (uint64_t *)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(uint64_t)); | |
1443 | } | |
1444 | ||
1445 | if (out->kvlist == NULL) | |
1446 | { | |
1447 | free_pmsg(out); | |
1448 | return ASL_STATUS_NO_MEMORY; | |
1449 | } | |
1450 | ||
1451 | out->kvlist[out->kvcount++] = ksid; | |
1452 | out->kvlist[out->kvcount++] = vsid; | |
1453 | } | |
1454 | } | |
1455 | ||
1456 | *p = out; | |
1457 | return Q_FAST; | |
1458 | } | |
1459 | ||
1460 | static uint32_t | |
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) | |
1462 | { | |
1463 | uint32_t status, what; | |
1464 | ||
1465 | *didmatch = 0; | |
1466 | ||
1467 | if (qtype == Q_FAIL) return ASL_STATUS_OK; | |
1468 | ||
1469 | if (qtype == Q_NULL) | |
1470 | { | |
1471 | if (*iopm == NULL) | |
1472 | { | |
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; | |
1476 | } | |
1477 | } | |
1478 | else if (qtype == Q_FAST) | |
1479 | { | |
1480 | if (qp == NULL) return ASL_STATUS_INVALID_ARG; | |
1481 | ||
1482 | what = PMSG_FETCH_STD; | |
1483 | if (qp->kvcount > 0) what = PMSG_FETCH_ALL; | |
1484 | ||
1485 | if (*iopm == NULL) | |
1486 | { | |
1487 | status = pmsg_fetch(s, slot, what, iopm); | |
1488 | if (status != ASL_STATUS_OK) return status; | |
1489 | if (*iopm == NULL) return ASL_STATUS_FAILED; | |
1490 | } | |
1491 | ||
1492 | status = pmsg_match(s, qp, *iopm); | |
1493 | if (status == 1) | |
1494 | { | |
1495 | if ((what == PMSG_FETCH_STD) && ((*iopm)->next != 0) && ((*iopm)->kvcount == 0)) | |
1496 | { | |
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; | |
1500 | } | |
1501 | } | |
1502 | else return ASL_STATUS_OK; | |
1503 | } | |
1504 | else if (qtype == Q_SLOW) | |
1505 | { | |
1506 | if (*iomsg == NULL) | |
1507 | { | |
1508 | if (*iopm == NULL) | |
1509 | { | |
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; | |
1513 | } | |
1514 | ||
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; | |
1519 | } | |
1520 | ||
1521 | status = 0; | |
1522 | if (asl_msg_cmp(q, *iomsg) != 0) status = 1; | |
1523 | if (status == 0) return ASL_STATUS_OK; | |
1524 | } | |
1525 | ||
1526 | *didmatch = 1; | |
1527 | ||
1528 | if (res == NULL) return ASL_STATUS_OK; | |
1529 | ||
1530 | if (*iomsg == NULL) | |
1531 | { | |
1532 | status = msg_decode(s, *iopm, iomsg); | |
1533 | if (status == ASL_STATUS_INVALID_MESSAGE) | |
1534 | { | |
1535 | *didmatch = 0; | |
1536 | return ASL_STATUS_OK; | |
1537 | } | |
1538 | ||
1539 | if (status != ASL_STATUS_OK) return status; | |
1540 | } | |
1541 | ||
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; | |
1545 | ||
1546 | (*res)->msg[(*res)->count++] = *iomsg; | |
1547 | ||
1548 | return ASL_STATUS_OK; | |
1549 | } | |
1550 | ||
1551 | static uint32_t | |
1552 | next_search_slot(asl_legacy1_t *s, uint32_t last_si, int32_t direction) | |
1553 | { | |
1554 | uint32_t i; | |
1555 | ||
1556 | if (direction >= 0) | |
1557 | { | |
1558 | for (i = last_si + 1; i < s->slotlist_count; i++) | |
1559 | { | |
1560 | if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; | |
1561 | } | |
1562 | ||
1563 | return ASL_INDEX_NULL; | |
1564 | } | |
1565 | ||
1566 | if (last_si == 0) return ASL_INDEX_NULL; | |
1567 | if (last_si > s->slotlist_count) return ASL_INDEX_NULL; | |
1568 | ||
1569 | for (i = last_si - 1; i > 0; i--) | |
1570 | { | |
1571 | if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; | |
1572 | } | |
1573 | ||
1574 | if (s->slotlist[0].type == DB_TYPE_MESSAGE) return 0; | |
1575 | ||
1576 | return ASL_INDEX_NULL; | |
1577 | } | |
1578 | ||
1579 | static uint32_t | |
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) | |
1581 | { | |
1582 | pmsg_t **outp, *pm; | |
1583 | uint32_t i, j, *outt; | |
1584 | *match = 0; | |
1585 | *qp = NULL; | |
1586 | *qtype = 0; | |
1587 | *count = 0; | |
1588 | ||
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; | |
1595 | ||
1596 | outp = (pmsg_t **)calloc(query->count, sizeof(pmsg_t *)); | |
1597 | if (outp == NULL) return ASL_STATUS_NO_MEMORY; | |
1598 | ||
1599 | outt = (uint32_t *)calloc(query->count, sizeof(uint32_t)); | |
1600 | if (outt == NULL) | |
1601 | { | |
1602 | free(outp); | |
1603 | return ASL_STATUS_NO_MEMORY; | |
1604 | } | |
1605 | ||
1606 | *match = 1; | |
1607 | ||
1608 | for (i = 0; i < query->count; i++) | |
1609 | { | |
1610 | pm = NULL; | |
1611 | outt[i] = query_to_pmsg(s, query->msg[i], &pm); | |
1612 | if (outt[i] <= ASL_STATUS_FAILED) | |
1613 | { | |
1614 | if (pm != NULL) free_pmsg(pm); | |
1615 | for (j = 0; j < i; j++) free_pmsg(outp[j]); | |
1616 | free(outp); | |
1617 | free(outt); | |
1618 | return ASL_STATUS_NO_MEMORY; | |
1619 | } | |
1620 | ||
1621 | outp[i] = pm; | |
1622 | } | |
1623 | ||
1624 | *count = query->count; | |
1625 | *qp = outp; | |
1626 | *qtype = outt; | |
1627 | return ASL_STATUS_OK; | |
1628 | } | |
1629 | ||
1630 | static void | |
1631 | match_worker_cleanup(pmsg_t **ql, uint32_t *qt, uint32_t n, asl_msg_list_t **res) | |
1632 | { | |
1633 | uint32_t i; | |
1634 | ||
1635 | if (ql != NULL) | |
1636 | { | |
1637 | for (i = 0; i < n; i++) free_pmsg(ql[i]); | |
1638 | free(ql); | |
1639 | } | |
1640 | ||
1641 | if (qt != NULL) free(qt); | |
1642 | ||
1643 | if (res != NULL) | |
1644 | { | |
1645 | for (i = 0; i < (*res)->count; i++) asl_free((*res)->msg[i]); | |
1646 | free(*res); | |
1647 | } | |
1648 | } | |
1649 | ||
1650 | /* | |
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) | |
1653 | * | |
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. | |
1656 | * | |
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. | |
1660 | * | |
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". | |
1665 | * | |
1666 | * If all queries are marked as "never matches", return NULL. | |
1667 | * | |
1668 | * match loop: | |
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. | |
1676 | * | |
1677 | * return results. | |
1678 | */ | |
1679 | static uint32_t | |
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) | |
1681 | { | |
1682 | uint32_t mx, si, slot, i, qcount, match, didmatch, status, *qtype; | |
1683 | uint64_t xid; | |
1684 | pmsg_t **qp, *iopmsg; | |
1685 | asl_msg_t *iomsg; | |
1686 | ||
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; | |
1691 | ||
1692 | if (res != NULL) *res = NULL; | |
1693 | if (idlist != NULL) *idlist = NULL; | |
1694 | ||
1695 | mx = 0; | |
1696 | ||
1697 | if (direction < 0) direction = -1; | |
1698 | else direction = 1; | |
1699 | ||
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); | |
1703 | ||
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; | |
1707 | ||
1708 | slot = s->slotlist[si].slot; | |
1709 | ||
1710 | status = query_list_to_pmsg_list(s, query, &match, &qp, &qtype, &qcount); | |
1711 | if (status != ASL_STATUS_OK) return status; | |
1712 | ||
1713 | /* | |
1714 | * initialize result list if we've been asked to return messages | |
1715 | */ | |
1716 | if (res != NULL) | |
1717 | { | |
1718 | *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); | |
1719 | if (*res == NULL) | |
1720 | { | |
1721 | match_worker_cleanup(qp, qtype, qcount, NULL); | |
1722 | return ASL_STATUS_NO_MEMORY; | |
1723 | } | |
1724 | } | |
1725 | ||
1726 | /* | |
1727 | * loop through records | |
1728 | */ | |
1729 | *idcount = 0; | |
1730 | while ((count == 0) || (*idcount < count)) | |
1731 | { | |
1732 | if (si == ASL_INDEX_NULL) break; | |
1733 | if (si >= s->slotlist_count) break; | |
1734 | ||
1735 | slot = s->slotlist[si].slot; | |
1736 | xid = s->slotlist[si].xid; | |
1737 | ||
1738 | *last_id = xid; | |
1739 | ||
1740 | iopmsg = NULL; | |
1741 | iomsg = NULL; | |
1742 | ||
1743 | didmatch = 0; | |
1744 | if (match == 0) | |
1745 | { | |
1746 | status = msg_match(s, Q_NULL, NULL, NULL, slot, &iopmsg, &iomsg, res, &didmatch); | |
1747 | free_pmsg(iopmsg); | |
1748 | if (didmatch == 0) | |
1749 | { | |
1750 | asl_free(iomsg); | |
1751 | iomsg = NULL; | |
1752 | } | |
1753 | else | |
1754 | { | |
1755 | if (idlist != NULL) | |
1756 | { | |
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; | |
1761 | } | |
1762 | ||
1763 | (*idcount)++; | |
1764 | } | |
1765 | ||
1766 | if (status != ASL_STATUS_OK) | |
1767 | { | |
1768 | match_worker_cleanup(qp, qtype, qcount, res); | |
1769 | return status; | |
1770 | } | |
1771 | } | |
1772 | else | |
1773 | { | |
1774 | for (i = 0; i < qcount; i++) | |
1775 | { | |
1776 | status = msg_match(s, qtype[i], qp[i], query->msg[i], slot, &iopmsg, &iomsg, res, &didmatch); | |
1777 | if (status != ASL_STATUS_OK) | |
1778 | { | |
1779 | free_pmsg(iopmsg); | |
1780 | asl_free(iomsg); | |
1781 | match_worker_cleanup(qp, qtype, qcount, res); | |
1782 | return status; | |
1783 | } | |
1784 | ||
1785 | if (didmatch == 1) | |
1786 | { | |
1787 | if (idlist != NULL) | |
1788 | { | |
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) | |
1792 | { | |
1793 | match_worker_cleanup(qp, qtype, qcount, res); | |
1794 | return ASL_STATUS_NO_MEMORY; | |
1795 | } | |
1796 | ||
1797 | (*idlist)[*idcount] = xid; | |
1798 | } | |
1799 | ||
1800 | (*idcount)++; | |
1801 | break; | |
1802 | } | |
1803 | } | |
1804 | ||
1805 | free_pmsg(iopmsg); | |
1806 | if ((didmatch == 0) || (res == NULL)) asl_free(iomsg); | |
1807 | } | |
1808 | ||
1809 | si = next_search_slot(s, si, direction); | |
1810 | } | |
1811 | ||
1812 | match_worker_cleanup(qp, qtype, qcount, NULL); | |
1813 | return status; | |
1814 | } | |
1815 | ||
1816 | uint32_t | |
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) | |
1818 | { | |
1819 | uint32_t idcount; | |
1820 | ||
1821 | idcount = 0; | |
1822 | return match_worker(s, query, res, last_id, NULL, &idcount, start_id, count, direction); | |
1823 | } |