]> git.saurik.com Git - apple/syslog.git/blob - libsystem_asl.tproj/src/asl_msg_list.c
syslog-385.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl_msg_list.c
1 /*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <asl.h>
30 #include <asl_core.h>
31 #include <asl_msg.h>
32 #include <asl_msg_list.h>
33
34 asl_msg_list_t *
35 asl_msg_list_new(void)
36 {
37 asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
38 if (out == NULL) return NULL;
39
40 out->asl_type = ASL_TYPE_LIST;
41 out->refcount = 1;
42
43 return out;
44 }
45
46 asl_msg_list_t *
47 asl_msg_list_new_count(uint32_t n)
48 {
49 asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t));
50 if (out == NULL) return NULL;
51
52 out->asl_type = ASL_TYPE_LIST;
53 out->refcount = 1;
54 out->count = n;
55
56 out->msg = (asl_msg_t **)reallocf(out->msg, out->count * sizeof(asl_msg_t *));
57 if (out->msg == NULL)
58 {
59 free(out);
60 return NULL;
61 }
62
63 return out;
64 }
65
66 asl_msg_list_t *
67 asl_msg_list_retain(asl_msg_list_t *list)
68 {
69 if (list == NULL) return NULL;
70 asl_retain((asl_object_t)list);
71 return list;
72 }
73
74 void
75 asl_msg_list_release(asl_msg_list_t *list)
76 {
77 if (list == NULL) return;
78 asl_release((asl_object_t)list);
79 }
80
81 char *
82 asl_msg_list_to_string(asl_msg_list_t *list, uint32_t *len)
83 {
84 uint32_t i;
85 char tmp[16];
86 char *out;
87 asl_string_t *str;
88
89 if (list == NULL) return NULL;
90 if (list->count == 0) return NULL;
91 if (list->msg == NULL) return NULL;
92
93 str = asl_string_new(ASL_ENCODE_ASL);
94 if (str == NULL) return NULL;
95
96 snprintf(tmp, sizeof(tmp), "%u", list->count);
97 asl_string_append(str, tmp);
98 asl_string_append_char_no_encoding(str, '\n');
99
100 for (i = 0; i < list->count; i++)
101 {
102 asl_string_append_asl_msg(str, list->msg[i]);
103 asl_string_append_char_no_encoding(str, '\n');
104 }
105
106 *len = asl_string_length(str);
107 out = asl_string_release_return_bytes(str);
108 return out;
109 }
110
111 asl_string_t *
112 asl_msg_list_to_asl_string(asl_msg_list_t *list, uint32_t encoding)
113 {
114 uint32_t i;
115 char tmp[16];
116 asl_string_t *str;
117
118 if (list == NULL) return NULL;
119 if (list->count == 0) return NULL;
120 if (list->msg == NULL) return NULL;
121
122 str = asl_string_new(encoding);
123 if (str == NULL) return NULL;
124
125 snprintf(tmp, sizeof(tmp), "%u", list->count);
126 asl_string_append(str, tmp);
127 asl_string_append_char_no_encoding(str, '\n');
128
129 for (i = 0; i < list->count; i++)
130 {
131 asl_string_append_asl_msg(str, list->msg[i]);
132 asl_string_append_char_no_encoding(str, '\n');
133 }
134
135 return str;
136 }
137
138 asl_msg_list_t *
139 asl_msg_list_from_string(const char *buf)
140 {
141 uint32_t i, n;
142 const char *p;
143 asl_msg_list_t *out;
144 asl_msg_t *m;
145
146 if (buf == NULL) return NULL;
147 p = buf;
148
149 n = atoi(buf);
150 if (n == 0) return NULL;
151
152 out = asl_msg_list_new();
153 if (out == NULL) return NULL;
154
155 for (i = 0; i < n; i++)
156 {
157 p = strchr(p, '\n');
158 if (p == NULL)
159 {
160 asl_msg_list_release(out);
161 return NULL;
162 }
163
164 p++;
165
166 m = asl_msg_from_string(p);
167 if (m == NULL)
168 {
169 asl_msg_list_release(out);
170 return NULL;
171 }
172
173 asl_msg_list_append(out, m);
174 asl_msg_release(m);
175 }
176
177 return out;
178 }
179
180 void
181 asl_msg_list_insert(asl_msg_list_t *list, uint32_t x, void *obj)
182 {
183 uint32_t i, j;
184 asl_object_private_t *oo = (asl_object_private_t *)obj;
185
186 if (list == NULL) return;
187 if (obj == NULL) return;
188 if (list->count == UINT32_MAX) return;
189
190 if (x >= list->count) x = list->count;
191
192 uint32_t type = asl_get_type((asl_object_t)oo);
193 uint32_t count = 0;
194
195 if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) count = 1;
196 else count = asl_object_count(oo);
197
198 if (count == 0) return;
199
200 uint64_t check = list->count;
201 check += count;
202 if (check > UINT32_MAX) return;
203
204 list->msg = (asl_msg_t **)reallocf(list->msg, (list->count + count) * sizeof(asl_msg_t *));
205 if (list->msg == NULL)
206 {
207 list->count = 0;
208 list->curr = 0;
209 return;
210 }
211
212 for (i = list->count, j = i - 1; i > x; i--, j--) list->msg[i] = list->msg[j];
213
214 asl_object_set_iteration_index(oo, 0);
215
216 if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY))
217 {
218 list->msg[x] = (asl_msg_t *)asl_retain((asl_object_t)oo);
219 }
220 else
221 {
222 for (i = x, j = 0; j < count; i++, j++) list->msg[i] = (asl_msg_t *)asl_object_next(oo);
223 }
224
225 asl_object_set_iteration_index(oo, 0);
226
227 list->count += count;
228 }
229
230 void
231 asl_msg_list_append(asl_msg_list_t *list, void *obj)
232 {
233 asl_msg_list_insert(list, UINT32_MAX, obj);
234 }
235
236 void
237 asl_msg_list_prepend(asl_msg_list_t *list, void *obj)
238 {
239 asl_msg_list_insert(list, 0, obj);
240 }
241
242 size_t
243 asl_msg_list_count(asl_msg_list_t *list)
244 {
245 if (list == NULL) return 0;
246 return list->count;
247 }
248
249 asl_msg_t *
250 asl_msg_list_get_index(asl_msg_list_t *list, size_t index)
251 {
252 asl_msg_t *out;
253
254 if (list == NULL) return NULL;
255 if (index >= list->count) return NULL;
256 if (list->msg == NULL)
257 {
258 list->curr = 0;
259 list->count = 0;
260 return NULL;
261 }
262
263 out = list->msg[index];
264 return out;
265 }
266
267 void
268 asl_msg_list_remove_index(asl_msg_list_t *list, size_t index)
269 {
270 uint32_t i, j;
271
272 if (list == NULL) return;
273 if (index >= list->count) return;
274 if (list->msg == NULL)
275 {
276 list->curr = 0;
277 list->count = 0;
278 return;
279 }
280
281 asl_msg_release(list->msg[index]);
282
283 for (i = index + 1, j = index; i < list->count; i++) list->msg[j] = list->msg[i];
284 list->count--;
285
286 list->msg = (asl_msg_t **)reallocf(list->msg, list->count * sizeof(asl_msg_t *));
287 if (list->msg == NULL)
288 {
289 list->count = 0;
290 list->curr = 0;
291 }
292 }
293
294 asl_msg_t *
295 asl_msg_list_next(asl_msg_list_t *list)
296 {
297 asl_msg_t *out;
298
299 if (list == NULL) return NULL;
300 if (list->curr >= list->count) return NULL;
301 if (list->msg == NULL)
302 {
303 list->curr = 0;
304 list->count = 0;
305 return NULL;
306 }
307
308 out = list->msg[list->curr];
309 list->curr++;
310 return out;
311 }
312
313 asl_msg_t *
314 asl_msg_list_prev(asl_msg_list_t *list)
315 {
316 asl_msg_t *out;
317
318 if (list == NULL) return NULL;
319 if (list->curr == 0) return NULL;
320 if (list->msg == NULL)
321 {
322 list->curr = 0;
323 list->count = 0;
324 return NULL;
325 }
326
327 if (list->curr > list->count) list->curr = list->count;
328
329 list->curr--;
330 out = list->msg[list->curr];
331 return out;
332 }
333
334 void
335 asl_msg_list_reset_iteration(asl_msg_list_t *list, size_t position)
336 {
337 if (list == NULL) return;
338
339 if (position > list->count) position = SIZE_MAX;
340 list->curr = position;
341 }
342
343 asl_msg_list_t *
344 asl_msg_list_search(asl_msg_list_t *list, asl_msg_t *query)
345 {
346 uint32_t i;
347 asl_msg_list_t *out = NULL;
348
349 if (list == NULL) return NULL;
350
351 if (list->msg == NULL)
352 {
353 list->curr = 0;
354 list->count = 0;
355 return NULL;
356 }
357
358 for (i = 0; i < list->count; i++)
359 {
360 int match = 0;
361 if (query == NULL) match = 1;
362 else match = asl_msg_cmp(query, list->msg[i]);
363
364 if (match != 0)
365 {
366 if (out == NULL) out = asl_msg_list_new();
367 if (out == NULL) return NULL;
368 asl_msg_list_append(out, list->msg[i]);
369 }
370 }
371
372 return out;
373 }
374
375 asl_msg_list_t *
376 asl_msg_list_match(asl_msg_list_t *list, asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction)
377 {
378 uint32_t i, end, n = 0;
379 struct timeval now, finish;
380 asl_msg_list_t *out = NULL;
381
382 if (list == NULL) return NULL;
383 if (list->msg == NULL)
384 {
385 list->curr = 0;
386 list->count = 0;
387 return NULL;
388 }
389
390 /* start the timer if a timeout was specified */
391 memset(&finish, 0, sizeof(struct timeval));
392 if (duration != 0)
393 {
394 if (gettimeofday(&finish, NULL) == 0)
395 {
396 finish.tv_sec += (duration / USEC_PER_SEC);
397 finish.tv_usec += (duration % USEC_PER_SEC);
398 if (finish.tv_usec > USEC_PER_SEC)
399 {
400 finish.tv_usec -= USEC_PER_SEC;
401 finish.tv_sec += 1;
402 }
403 }
404 else
405 {
406 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
407 memset(&finish, 0, sizeof(struct timeval));
408 }
409 }
410
411 end = list->count - 1;
412 if (direction >= 0)
413 {
414 if (start >= list->count)
415 {
416 if (last != NULL) *last = list->count;
417 return 0;
418 }
419
420 direction = 1;
421 }
422 else
423 {
424 if (start >= list->count) start = list->count - 1;
425 end = 0;
426 direction = -1;
427 }
428
429 i = start;
430
431 do
432 {
433 int match = 0;
434 if (qlist == NULL) match = 1;
435 else match = asl_msg_cmp_list(list->msg[i], qlist);
436
437 if (last != NULL) *last = i;
438
439 if (match != 0)
440 {
441 if (out == NULL) out = asl_msg_list_new();
442 if (out == NULL) return NULL;
443
444 asl_msg_list_append(out, list->msg[i]);
445 n++;
446 }
447
448 if (n >= count) return n;
449
450 /* check the timer */
451 if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0))
452 {
453 if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) return n;
454 }
455
456 i += direction;
457 } while (i != end);
458
459 return out;
460 }
461
462 #pragma mark -
463 #pragma mark asl_object support
464
465 static asl_object_private_t *
466 _jump_alloc(uint32_t type)
467 {
468 return (asl_object_private_t *)asl_msg_list_new();
469 }
470
471 static void
472 _jump_dealloc(asl_object_private_t *obj)
473 {
474 asl_msg_list_t *list = (asl_msg_list_t *)obj;
475
476 if (list == NULL) return;
477 if (list->msg != NULL)
478 {
479 uint32_t i;
480 for (i = 0; i < list->count; i++) asl_msg_release(list->msg[i]);
481 free(list->msg);
482 }
483
484 free(list);
485 }
486
487 static size_t
488 _jump_count(asl_object_private_t *obj)
489 {
490 return asl_msg_list_count((asl_msg_list_t *)obj);
491 }
492
493 static asl_object_private_t *
494 _jump_next(asl_object_private_t *obj)
495 {
496 return (asl_object_private_t *)asl_msg_list_next((asl_msg_list_t *)obj);
497 }
498
499 static asl_object_private_t *
500 _jump_prev(asl_object_private_t *obj)
501 {
502 return (asl_object_private_t *)asl_msg_list_prev((asl_msg_list_t *)obj);
503 }
504
505 static asl_object_private_t *
506 _jump_get_object_at_index(asl_object_private_t *obj, size_t n)
507 {
508 return (asl_object_private_t *)asl_msg_list_get_index((asl_msg_list_t *)obj, n);
509 }
510
511 static void
512 _jump_set_iteration_index(asl_object_private_t *obj, size_t n)
513 {
514 asl_msg_list_reset_iteration((asl_msg_list_t *)obj, n);
515 }
516
517 static void
518 _jump_remove_object_at_index(asl_object_private_t *obj, size_t n)
519 {
520 asl_msg_list_remove_index((asl_msg_list_t *)obj, n);
521 }
522
523 static void
524 _jump_append(asl_object_private_t *obj, asl_object_private_t *newobj, void *addr)
525 {
526 int type = asl_get_type((asl_object_t)newobj);
527 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return;
528
529 asl_msg_list_append((asl_msg_list_t *)obj, newobj);
530 }
531
532 static void
533 _jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj)
534 {
535 int type = asl_get_type((asl_object_t)newobj);
536 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return;
537
538 asl_msg_list_prepend((asl_msg_list_t *)obj, newobj);
539 }
540
541 static asl_object_private_t *
542 _jump_search(asl_object_private_t *obj, asl_object_private_t *query)
543 {
544 int type = asl_get_type((asl_object_t)query);
545
546 if ((query != NULL) && (type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return NULL;
547
548 asl_msg_list_t *out = asl_msg_list_search((asl_msg_list_t *)obj, (asl_msg_t *)query);
549 if (out == NULL) return NULL;
550 return (asl_object_private_t *)out;
551 }
552
553 static asl_object_private_t *
554 _jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir)
555 {
556 int type = asl_get_type((asl_object_t)qlist);
557
558 if ((qlist != NULL) && (type != ASL_TYPE_LIST)) return NULL;
559
560 return (asl_object_private_t *)asl_msg_list_match((asl_msg_list_t *)obj, (asl_msg_list_t *)qlist, last, start, count, duration, dir);
561 }
562
563 __private_extern__ const asl_jump_table_t *
564 asl_msg_list_jump_table()
565 {
566 static const asl_jump_table_t jump =
567 {
568 .alloc = &_jump_alloc,
569 .dealloc = &_jump_dealloc,
570 .set_key_val_op = NULL,
571 .unset_key = NULL,
572 .get_val_op_for_key = NULL,
573 .get_key_val_op_at_index = NULL,
574 .count = &_jump_count,
575 .next = &_jump_next,
576 .prev = &_jump_prev,
577 .get_object_at_index = &_jump_get_object_at_index,
578 .set_iteration_index = &_jump_set_iteration_index,
579 .remove_object_at_index = &_jump_remove_object_at_index,
580 .append = &_jump_append,
581 .prepend = &_jump_prepend,
582 .search = &_jump_search,
583 .match = &_jump_match
584 };
585
586 return &jump;
587 }