]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/sd-journal.c
journald: cache cgroup root path, instead of querying it on every incoming log message
[thirdparty/systemd.git] / src / journal / sd-journal.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stddef.h>
25 #include <unistd.h>
26 #include <sys/inotify.h>
27 #include <sys/poll.h>
28 #include <sys/vfs.h>
29 #include <linux/magic.h>
30
31 #include "sd-journal.h"
32 #include "journal-def.h"
33 #include "journal-file.h"
34 #include "hashmap.h"
35 #include "list.h"
36 #include "strv.h"
37 #include "path-util.h"
38 #include "lookup3.h"
39 #include "compress.h"
40 #include "journal-internal.h"
41 #include "missing.h"
42 #include "catalog.h"
43 #include "replace-var.h"
44 #include "fileio.h"
45
46 #define JOURNAL_FILES_MAX 1024
47
48 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
49
50 #define REPLACE_VAR_MAX 256
51
52 #define DEFAULT_DATA_THRESHOLD (64*1024)
53
54 static bool journal_pid_changed(sd_journal *j) {
55 assert(j);
56
57 /* We don't support people creating a journal object and
58 * keeping it around over a fork(). Let's complain. */
59
60 return j->original_pid != getpid();
61 }
62
63 /* We return an error here only if we didn't manage to
64 memorize the real error. */
65 static int set_put_error(sd_journal *j, int r) {
66 int k;
67
68 if (r >= 0)
69 return r;
70
71 k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func);
72 if (k < 0)
73 return k;
74
75 return set_put(j->errors, INT_TO_PTR(r));
76 }
77
78 static void detach_location(sd_journal *j) {
79 Iterator i;
80 JournalFile *f;
81
82 assert(j);
83
84 j->current_file = NULL;
85 j->current_field = 0;
86
87 HASHMAP_FOREACH(f, j->files, i)
88 f->current_offset = 0;
89 }
90
91 static void reset_location(sd_journal *j) {
92 assert(j);
93
94 detach_location(j);
95 zero(j->current_location);
96 }
97
98 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
99 assert(l);
100 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
101 assert(f);
102 assert(o->object.type == OBJECT_ENTRY);
103
104 l->type = type;
105 l->seqnum = le64toh(o->entry.seqnum);
106 l->seqnum_id = f->header->seqnum_id;
107 l->realtime = le64toh(o->entry.realtime);
108 l->monotonic = le64toh(o->entry.monotonic);
109 l->boot_id = o->entry.boot_id;
110 l->xor_hash = le64toh(o->entry.xor_hash);
111
112 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
113 }
114
115 static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o,
116 direction_t direction, uint64_t offset) {
117 assert(j);
118 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
119 assert(f);
120 assert(o);
121
122 init_location(&j->current_location, type, f, o);
123
124 j->current_file = f;
125 j->current_field = 0;
126
127 f->last_direction = direction;
128 f->current_offset = offset;
129 }
130
131 static int match_is_valid(const void *data, size_t size) {
132 const char *b, *p;
133
134 assert(data);
135
136 if (size < 2)
137 return false;
138
139 if (startswith(data, "__"))
140 return false;
141
142 b = data;
143 for (p = b; p < b + size; p++) {
144
145 if (*p == '=')
146 return p > b;
147
148 if (*p == '_')
149 continue;
150
151 if (*p >= 'A' && *p <= 'Z')
152 continue;
153
154 if (*p >= '0' && *p <= '9')
155 continue;
156
157 return false;
158 }
159
160 return false;
161 }
162
163 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
164 const uint8_t *a = _a, *b = _b;
165 size_t j;
166
167 for (j = 0; j < s && j < t; j++) {
168
169 if (a[j] != b[j])
170 return false;
171
172 if (a[j] == '=')
173 return true;
174 }
175
176 assert_not_reached("\"=\" not found");
177 }
178
179 static Match *match_new(Match *p, MatchType t) {
180 Match *m;
181
182 m = new0(Match, 1);
183 if (!m)
184 return NULL;
185
186 m->type = t;
187
188 if (p) {
189 m->parent = p;
190 LIST_PREPEND(matches, p->matches, m);
191 }
192
193 return m;
194 }
195
196 static void match_free(Match *m) {
197 assert(m);
198
199 while (m->matches)
200 match_free(m->matches);
201
202 if (m->parent)
203 LIST_REMOVE(matches, m->parent->matches, m);
204
205 free(m->data);
206 free(m);
207 }
208
209 static void match_free_if_empty(Match *m) {
210 if (!m || m->matches)
211 return;
212
213 match_free(m);
214 }
215
216 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
217 Match *l3, *l4, *add_here = NULL, *m;
218 le64_t le_hash;
219
220 assert_return(j, -EINVAL);
221 assert_return(!journal_pid_changed(j), -ECHILD);
222 assert_return(data, -EINVAL);
223
224 if (size == 0)
225 size = strlen(data);
226
227 assert_return(match_is_valid(data, size), -EINVAL);
228
229 /* level 0: AND term
230 * level 1: OR terms
231 * level 2: AND terms
232 * level 3: OR terms
233 * level 4: concrete matches */
234
235 if (!j->level0) {
236 j->level0 = match_new(NULL, MATCH_AND_TERM);
237 if (!j->level0)
238 return -ENOMEM;
239 }
240
241 if (!j->level1) {
242 j->level1 = match_new(j->level0, MATCH_OR_TERM);
243 if (!j->level1)
244 return -ENOMEM;
245 }
246
247 if (!j->level2) {
248 j->level2 = match_new(j->level1, MATCH_AND_TERM);
249 if (!j->level2)
250 return -ENOMEM;
251 }
252
253 assert(j->level0->type == MATCH_AND_TERM);
254 assert(j->level1->type == MATCH_OR_TERM);
255 assert(j->level2->type == MATCH_AND_TERM);
256
257 le_hash = htole64(hash64(data, size));
258
259 LIST_FOREACH(matches, l3, j->level2->matches) {
260 assert(l3->type == MATCH_OR_TERM);
261
262 LIST_FOREACH(matches, l4, l3->matches) {
263 assert(l4->type == MATCH_DISCRETE);
264
265 /* Exactly the same match already? Then ignore
266 * this addition */
267 if (l4->le_hash == le_hash &&
268 l4->size == size &&
269 memcmp(l4->data, data, size) == 0)
270 return 0;
271
272 /* Same field? Then let's add this to this OR term */
273 if (same_field(data, size, l4->data, l4->size)) {
274 add_here = l3;
275 break;
276 }
277 }
278
279 if (add_here)
280 break;
281 }
282
283 if (!add_here) {
284 add_here = match_new(j->level2, MATCH_OR_TERM);
285 if (!add_here)
286 goto fail;
287 }
288
289 m = match_new(add_here, MATCH_DISCRETE);
290 if (!m)
291 goto fail;
292
293 m->le_hash = le_hash;
294 m->size = size;
295 m->data = memdup(data, size);
296 if (!m->data)
297 goto fail;
298
299 detach_location(j);
300
301 return 0;
302
303 fail:
304 match_free_if_empty(add_here);
305 match_free_if_empty(j->level2);
306 match_free_if_empty(j->level1);
307 match_free_if_empty(j->level0);
308
309 return -ENOMEM;
310 }
311
312 _public_ int sd_journal_add_conjunction(sd_journal *j) {
313 assert_return(j, -EINVAL);
314 assert_return(!journal_pid_changed(j), -ECHILD);
315
316 if (!j->level0)
317 return 0;
318
319 if (!j->level1)
320 return 0;
321
322 if (!j->level1->matches)
323 return 0;
324
325 j->level1 = NULL;
326 j->level2 = NULL;
327
328 return 0;
329 }
330
331 _public_ int sd_journal_add_disjunction(sd_journal *j) {
332 assert_return(j, -EINVAL);
333 assert_return(!journal_pid_changed(j), -ECHILD);
334
335 if (!j->level0)
336 return 0;
337
338 if (!j->level1)
339 return 0;
340
341 if (!j->level2)
342 return 0;
343
344 if (!j->level2->matches)
345 return 0;
346
347 j->level2 = NULL;
348 return 0;
349 }
350
351 static char *match_make_string(Match *m) {
352 char *p, *r;
353 Match *i;
354 bool enclose = false;
355
356 if (!m)
357 return strdup("none");
358
359 if (m->type == MATCH_DISCRETE)
360 return strndup(m->data, m->size);
361
362 p = NULL;
363 LIST_FOREACH(matches, i, m->matches) {
364 char *t, *k;
365
366 t = match_make_string(i);
367 if (!t) {
368 free(p);
369 return NULL;
370 }
371
372 if (p) {
373 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
374 free(p);
375 free(t);
376
377 if (!k)
378 return NULL;
379
380 p = k;
381
382 enclose = true;
383 } else
384 p = t;
385 }
386
387 if (enclose) {
388 r = strjoin("(", p, ")", NULL);
389 free(p);
390 return r;
391 }
392
393 return p;
394 }
395
396 char *journal_make_match_string(sd_journal *j) {
397 assert(j);
398
399 return match_make_string(j->level0);
400 }
401
402 _public_ void sd_journal_flush_matches(sd_journal *j) {
403 if (!j)
404 return;
405
406 if (j->level0)
407 match_free(j->level0);
408
409 j->level0 = j->level1 = j->level2 = NULL;
410
411 detach_location(j);
412 }
413
414 static int compare_entry_order(JournalFile *af, Object *_ao,
415 JournalFile *bf, uint64_t bp) {
416
417 uint64_t a, b;
418 Object *ao, *bo;
419 int r;
420
421 assert(af);
422 assert(bf);
423 assert(_ao);
424
425 /* The mmap cache might invalidate the object from the first
426 * file if we look at the one from the second file. Hence
427 * temporarily copy the header of the first one, and look at
428 * that only. */
429 ao = alloca(offsetof(EntryObject, items));
430 memcpy(ao, _ao, offsetof(EntryObject, items));
431
432 r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo);
433 if (r < 0)
434 return strcmp(af->path, bf->path);
435
436 /* We operate on two different files here, hence we can access
437 * two objects at the same time, which we normally can't.
438 *
439 * If contents and timestamps match, these entries are
440 * identical, even if the seqnum does not match */
441
442 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) &&
443 ao->entry.monotonic == bo->entry.monotonic &&
444 ao->entry.realtime == bo->entry.realtime &&
445 ao->entry.xor_hash == bo->entry.xor_hash)
446 return 0;
447
448 if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
449
450 /* If this is from the same seqnum source, compare
451 * seqnums */
452 a = le64toh(ao->entry.seqnum);
453 b = le64toh(bo->entry.seqnum);
454
455 if (a < b)
456 return -1;
457 if (a > b)
458 return 1;
459
460 /* Wow! This is weird, different data but the same
461 * seqnums? Something is borked, but let's make the
462 * best of it and compare by time. */
463 }
464
465 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) {
466
467 /* If the boot id matches compare monotonic time */
468 a = le64toh(ao->entry.monotonic);
469 b = le64toh(bo->entry.monotonic);
470
471 if (a < b)
472 return -1;
473 if (a > b)
474 return 1;
475 }
476
477 /* Otherwise compare UTC time */
478 a = le64toh(ao->entry.realtime);
479 b = le64toh(bo->entry.realtime);
480
481 if (a < b)
482 return -1;
483 if (a > b)
484 return 1;
485
486 /* Finally, compare by contents */
487 a = le64toh(ao->entry.xor_hash);
488 b = le64toh(bo->entry.xor_hash);
489
490 if (a < b)
491 return -1;
492 if (a > b)
493 return 1;
494
495 return 0;
496 }
497
498 _pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
499 uint64_t a;
500
501 assert(af);
502 assert(ao);
503 assert(l);
504 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
505
506 if (l->monotonic_set &&
507 sd_id128_equal(ao->entry.boot_id, l->boot_id) &&
508 l->realtime_set &&
509 le64toh(ao->entry.realtime) == l->realtime &&
510 l->xor_hash_set &&
511 le64toh(ao->entry.xor_hash) == l->xor_hash)
512 return 0;
513
514 if (l->seqnum_set &&
515 sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) {
516
517 a = le64toh(ao->entry.seqnum);
518
519 if (a < l->seqnum)
520 return -1;
521 if (a > l->seqnum)
522 return 1;
523 }
524
525 if (l->monotonic_set &&
526 sd_id128_equal(ao->entry.boot_id, l->boot_id)) {
527
528 a = le64toh(ao->entry.monotonic);
529
530 if (a < l->monotonic)
531 return -1;
532 if (a > l->monotonic)
533 return 1;
534 }
535
536 if (l->realtime_set) {
537
538 a = le64toh(ao->entry.realtime);
539
540 if (a < l->realtime)
541 return -1;
542 if (a > l->realtime)
543 return 1;
544 }
545
546 if (l->xor_hash_set) {
547 a = le64toh(ao->entry.xor_hash);
548
549 if (a < l->xor_hash)
550 return -1;
551 if (a > l->xor_hash)
552 return 1;
553 }
554
555 return 0;
556 }
557
558 static int next_for_match(
559 sd_journal *j,
560 Match *m,
561 JournalFile *f,
562 uint64_t after_offset,
563 direction_t direction,
564 Object **ret,
565 uint64_t *offset) {
566
567 int r;
568 uint64_t np = 0;
569 Object *n;
570
571 assert(j);
572 assert(m);
573 assert(f);
574
575 if (m->type == MATCH_DISCRETE) {
576 uint64_t dp;
577
578 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
579 if (r <= 0)
580 return r;
581
582 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
583
584 } else if (m->type == MATCH_OR_TERM) {
585 Match *i;
586
587 /* Find the earliest match beyond after_offset */
588
589 LIST_FOREACH(matches, i, m->matches) {
590 uint64_t cp;
591
592 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
593 if (r < 0)
594 return r;
595 else if (r > 0) {
596 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
597 np = cp;
598 }
599 }
600
601 if (np == 0)
602 return 0;
603
604 } else if (m->type == MATCH_AND_TERM) {
605 Match *i, *last_moved;
606
607 /* Always jump to the next matching entry and repeat
608 * this until we find an offset that matches for all
609 * matches. */
610
611 if (!m->matches)
612 return 0;
613
614 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
615 if (r <= 0)
616 return r;
617
618 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
619 last_moved = m->matches;
620
621 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
622 uint64_t cp;
623
624 r = next_for_match(j, i, f, np, direction, NULL, &cp);
625 if (r <= 0)
626 return r;
627
628 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
629 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
630 np = cp;
631 last_moved = i;
632 }
633 }
634 }
635
636 assert(np > 0);
637
638 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
639 if (r < 0)
640 return r;
641
642 if (ret)
643 *ret = n;
644 if (offset)
645 *offset = np;
646
647 return 1;
648 }
649
650 static int find_location_for_match(
651 sd_journal *j,
652 Match *m,
653 JournalFile *f,
654 direction_t direction,
655 Object **ret,
656 uint64_t *offset) {
657
658 int r;
659
660 assert(j);
661 assert(m);
662 assert(f);
663
664 if (m->type == MATCH_DISCRETE) {
665 uint64_t dp;
666
667 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
668 if (r <= 0)
669 return r;
670
671 /* FIXME: missing: find by monotonic */
672
673 if (j->current_location.type == LOCATION_HEAD)
674 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
675 if (j->current_location.type == LOCATION_TAIL)
676 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
677 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
678 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
679 if (j->current_location.monotonic_set) {
680 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
681 if (r != -ENOENT)
682 return r;
683 }
684 if (j->current_location.realtime_set)
685 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
686
687 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
688
689 } else if (m->type == MATCH_OR_TERM) {
690 uint64_t np = 0;
691 Object *n;
692 Match *i;
693
694 /* Find the earliest match */
695
696 LIST_FOREACH(matches, i, m->matches) {
697 uint64_t cp;
698
699 r = find_location_for_match(j, i, f, direction, NULL, &cp);
700 if (r < 0)
701 return r;
702 else if (r > 0) {
703 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
704 np = cp;
705 }
706 }
707
708 if (np == 0)
709 return 0;
710
711 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
712 if (r < 0)
713 return r;
714
715 if (ret)
716 *ret = n;
717 if (offset)
718 *offset = np;
719
720 return 1;
721
722 } else {
723 Match *i;
724 uint64_t np = 0;
725
726 assert(m->type == MATCH_AND_TERM);
727
728 /* First jump to the last match, and then find the
729 * next one where all matches match */
730
731 if (!m->matches)
732 return 0;
733
734 LIST_FOREACH(matches, i, m->matches) {
735 uint64_t cp;
736
737 r = find_location_for_match(j, i, f, direction, NULL, &cp);
738 if (r <= 0)
739 return r;
740
741 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
742 np = cp;
743 }
744
745 return next_for_match(j, m, f, np, direction, ret, offset);
746 }
747 }
748
749 static int find_location_with_matches(
750 sd_journal *j,
751 JournalFile *f,
752 direction_t direction,
753 Object **ret,
754 uint64_t *offset) {
755
756 int r;
757
758 assert(j);
759 assert(f);
760 assert(ret);
761 assert(offset);
762
763 if (!j->level0) {
764 /* No matches is simple */
765
766 if (j->current_location.type == LOCATION_HEAD)
767 return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset);
768 if (j->current_location.type == LOCATION_TAIL)
769 return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset);
770 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
771 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
772 if (j->current_location.monotonic_set) {
773 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
774 if (r != -ENOENT)
775 return r;
776 }
777 if (j->current_location.realtime_set)
778 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
779
780 return journal_file_next_entry(f, NULL, 0, direction, ret, offset);
781 } else
782 return find_location_for_match(j, j->level0, f, direction, ret, offset);
783 }
784
785 static int next_with_matches(
786 sd_journal *j,
787 JournalFile *f,
788 direction_t direction,
789 Object **ret,
790 uint64_t *offset) {
791
792 Object *c;
793 uint64_t cp;
794
795 assert(j);
796 assert(f);
797 assert(ret);
798 assert(offset);
799
800 c = *ret;
801 cp = *offset;
802
803 /* No matches is easy. We simple advance the file
804 * pointer by one. */
805 if (!j->level0)
806 return journal_file_next_entry(f, c, cp, direction, ret, offset);
807
808 /* If we have a match then we look for the next matching entry
809 * with an offset at least one step larger */
810 return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
811 }
812
813 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
814 Object *c;
815 uint64_t cp;
816 int r;
817
818 assert(j);
819 assert(f);
820
821 if (f->last_direction == direction && f->current_offset > 0) {
822 cp = f->current_offset;
823
824 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
825 if (r < 0)
826 return r;
827
828 r = next_with_matches(j, f, direction, &c, &cp);
829 if (r <= 0)
830 return r;
831 } else {
832 r = find_location_with_matches(j, f, direction, &c, &cp);
833 if (r <= 0)
834 return r;
835 }
836
837 /* OK, we found the spot, now let's advance until an entry
838 * that is actually different from what we were previously
839 * looking at. This is necessary to handle entries which exist
840 * in two (or more) journal files, and which shall all be
841 * suppressed but one. */
842
843 for (;;) {
844 bool found;
845
846 if (j->current_location.type == LOCATION_DISCRETE) {
847 int k;
848
849 k = compare_with_location(f, c, &j->current_location);
850 if (direction == DIRECTION_DOWN)
851 found = k > 0;
852 else
853 found = k < 0;
854 } else
855 found = true;
856
857 if (found) {
858 if (ret)
859 *ret = c;
860 if (offset)
861 *offset = cp;
862 return 1;
863 }
864
865 r = next_with_matches(j, f, direction, &c, &cp);
866 if (r <= 0)
867 return r;
868 }
869 }
870
871 static int real_journal_next(sd_journal *j, direction_t direction) {
872 JournalFile *f, *new_file = NULL;
873 uint64_t new_offset = 0;
874 Object *o;
875 uint64_t p;
876 Iterator i;
877 int r;
878
879 assert_return(j, -EINVAL);
880 assert_return(!journal_pid_changed(j), -ECHILD);
881
882 HASHMAP_FOREACH(f, j->files, i) {
883 bool found;
884
885 r = next_beyond_location(j, f, direction, &o, &p);
886 if (r < 0) {
887 log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r));
888 continue;
889 } else if (r == 0)
890 continue;
891
892 if (!new_file)
893 found = true;
894 else {
895 int k;
896
897 k = compare_entry_order(f, o, new_file, new_offset);
898
899 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
900 }
901
902 if (found) {
903 new_file = f;
904 new_offset = p;
905 }
906 }
907
908 if (!new_file)
909 return 0;
910
911 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o);
912 if (r < 0)
913 return r;
914
915 set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset);
916
917 return 1;
918 }
919
920 _public_ int sd_journal_next(sd_journal *j) {
921 return real_journal_next(j, DIRECTION_DOWN);
922 }
923
924 _public_ int sd_journal_previous(sd_journal *j) {
925 return real_journal_next(j, DIRECTION_UP);
926 }
927
928 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
929 int c = 0, r;
930
931 assert_return(j, -EINVAL);
932 assert_return(!journal_pid_changed(j), -ECHILD);
933
934 if (skip == 0) {
935 /* If this is not a discrete skip, then at least
936 * resolve the current location */
937 if (j->current_location.type != LOCATION_DISCRETE)
938 return real_journal_next(j, direction);
939
940 return 0;
941 }
942
943 do {
944 r = real_journal_next(j, direction);
945 if (r < 0)
946 return r;
947
948 if (r == 0)
949 return c;
950
951 skip--;
952 c++;
953 } while (skip > 0);
954
955 return c;
956 }
957
958 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
959 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
960 }
961
962 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
963 return real_journal_next_skip(j, DIRECTION_UP, skip);
964 }
965
966 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
967 Object *o;
968 int r;
969 char bid[33], sid[33];
970
971 assert_return(j, -EINVAL);
972 assert_return(!journal_pid_changed(j), -ECHILD);
973 assert_return(cursor, -EINVAL);
974
975 if (!j->current_file || j->current_file->current_offset <= 0)
976 return -EADDRNOTAVAIL;
977
978 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
979 if (r < 0)
980 return r;
981
982 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
983 sd_id128_to_string(o->entry.boot_id, bid);
984
985 if (asprintf(cursor,
986 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
987 sid, le64toh(o->entry.seqnum),
988 bid, le64toh(o->entry.monotonic),
989 le64toh(o->entry.realtime),
990 le64toh(o->entry.xor_hash)) < 0)
991 return -ENOMEM;
992
993 return 0;
994 }
995
996 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
997 char *w, *state;
998 size_t l;
999 unsigned long long seqnum, monotonic, realtime, xor_hash;
1000 bool
1001 seqnum_id_set = false,
1002 seqnum_set = false,
1003 boot_id_set = false,
1004 monotonic_set = false,
1005 realtime_set = false,
1006 xor_hash_set = false;
1007 sd_id128_t seqnum_id, boot_id;
1008
1009 assert_return(j, -EINVAL);
1010 assert_return(!journal_pid_changed(j), -ECHILD);
1011 assert_return(!isempty(cursor), -EINVAL);
1012
1013 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1014 char *item;
1015 int k = 0;
1016
1017 if (l < 2 || w[1] != '=')
1018 return -EINVAL;
1019
1020 item = strndup(w, l);
1021 if (!item)
1022 return -ENOMEM;
1023
1024 switch (w[0]) {
1025
1026 case 's':
1027 seqnum_id_set = true;
1028 k = sd_id128_from_string(item+2, &seqnum_id);
1029 break;
1030
1031 case 'i':
1032 seqnum_set = true;
1033 if (sscanf(item+2, "%llx", &seqnum) != 1)
1034 k = -EINVAL;
1035 break;
1036
1037 case 'b':
1038 boot_id_set = true;
1039 k = sd_id128_from_string(item+2, &boot_id);
1040 break;
1041
1042 case 'm':
1043 monotonic_set = true;
1044 if (sscanf(item+2, "%llx", &monotonic) != 1)
1045 k = -EINVAL;
1046 break;
1047
1048 case 't':
1049 realtime_set = true;
1050 if (sscanf(item+2, "%llx", &realtime) != 1)
1051 k = -EINVAL;
1052 break;
1053
1054 case 'x':
1055 xor_hash_set = true;
1056 if (sscanf(item+2, "%llx", &xor_hash) != 1)
1057 k = -EINVAL;
1058 break;
1059 }
1060
1061 free(item);
1062
1063 if (k < 0)
1064 return k;
1065 }
1066
1067 if ((!seqnum_set || !seqnum_id_set) &&
1068 (!monotonic_set || !boot_id_set) &&
1069 !realtime_set)
1070 return -EINVAL;
1071
1072 reset_location(j);
1073
1074 j->current_location.type = LOCATION_SEEK;
1075
1076 if (realtime_set) {
1077 j->current_location.realtime = (uint64_t) realtime;
1078 j->current_location.realtime_set = true;
1079 }
1080
1081 if (seqnum_set && seqnum_id_set) {
1082 j->current_location.seqnum = (uint64_t) seqnum;
1083 j->current_location.seqnum_id = seqnum_id;
1084 j->current_location.seqnum_set = true;
1085 }
1086
1087 if (monotonic_set && boot_id_set) {
1088 j->current_location.monotonic = (uint64_t) monotonic;
1089 j->current_location.boot_id = boot_id;
1090 j->current_location.monotonic_set = true;
1091 }
1092
1093 if (xor_hash_set) {
1094 j->current_location.xor_hash = (uint64_t) xor_hash;
1095 j->current_location.xor_hash_set = true;
1096 }
1097
1098 return 0;
1099 }
1100
1101 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1102 int r;
1103 char *w, *state;
1104 size_t l;
1105 Object *o;
1106
1107 assert_return(j, -EINVAL);
1108 assert_return(!journal_pid_changed(j), -ECHILD);
1109 assert_return(!isempty(cursor), -EINVAL);
1110
1111 if (!j->current_file || j->current_file->current_offset <= 0)
1112 return -EADDRNOTAVAIL;
1113
1114 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1115 if (r < 0)
1116 return r;
1117
1118 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1119 _cleanup_free_ char *item = NULL;
1120 sd_id128_t id;
1121 unsigned long long ll;
1122 int k = 0;
1123
1124 if (l < 2 || w[1] != '=')
1125 return -EINVAL;
1126
1127 item = strndup(w, l);
1128 if (!item)
1129 return -ENOMEM;
1130
1131 switch (w[0]) {
1132
1133 case 's':
1134 k = sd_id128_from_string(item+2, &id);
1135 if (k < 0)
1136 return k;
1137 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1138 return 0;
1139 break;
1140
1141 case 'i':
1142 if (sscanf(item+2, "%llx", &ll) != 1)
1143 return -EINVAL;
1144 if (ll != le64toh(o->entry.seqnum))
1145 return 0;
1146 break;
1147
1148 case 'b':
1149 k = sd_id128_from_string(item+2, &id);
1150 if (k < 0)
1151 return k;
1152 if (!sd_id128_equal(id, o->entry.boot_id))
1153 return 0;
1154 break;
1155
1156 case 'm':
1157 if (sscanf(item+2, "%llx", &ll) != 1)
1158 return -EINVAL;
1159 if (ll != le64toh(o->entry.monotonic))
1160 return 0;
1161 break;
1162
1163 case 't':
1164 if (sscanf(item+2, "%llx", &ll) != 1)
1165 return -EINVAL;
1166 if (ll != le64toh(o->entry.realtime))
1167 return 0;
1168 break;
1169
1170 case 'x':
1171 if (sscanf(item+2, "%llx", &ll) != 1)
1172 return -EINVAL;
1173 if (ll != le64toh(o->entry.xor_hash))
1174 return 0;
1175 break;
1176 }
1177 }
1178
1179 return 1;
1180 }
1181
1182
1183 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1184 assert_return(j, -EINVAL);
1185 assert_return(!journal_pid_changed(j), -ECHILD);
1186
1187 reset_location(j);
1188 j->current_location.type = LOCATION_SEEK;
1189 j->current_location.boot_id = boot_id;
1190 j->current_location.monotonic = usec;
1191 j->current_location.monotonic_set = true;
1192
1193 return 0;
1194 }
1195
1196 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1197 assert_return(j, -EINVAL);
1198 assert_return(!journal_pid_changed(j), -ECHILD);
1199
1200 reset_location(j);
1201 j->current_location.type = LOCATION_SEEK;
1202 j->current_location.realtime = usec;
1203 j->current_location.realtime_set = true;
1204
1205 return 0;
1206 }
1207
1208 _public_ int sd_journal_seek_head(sd_journal *j) {
1209 assert_return(j, -EINVAL);
1210 assert_return(!journal_pid_changed(j), -ECHILD);
1211
1212 reset_location(j);
1213 j->current_location.type = LOCATION_HEAD;
1214
1215 return 0;
1216 }
1217
1218 _public_ int sd_journal_seek_tail(sd_journal *j) {
1219 assert_return(j, -EINVAL);
1220 assert_return(!journal_pid_changed(j), -ECHILD);
1221
1222 reset_location(j);
1223 j->current_location.type = LOCATION_TAIL;
1224
1225 return 0;
1226 }
1227
1228 static void check_network(sd_journal *j, int fd) {
1229 struct statfs sfs;
1230
1231 assert(j);
1232
1233 if (j->on_network)
1234 return;
1235
1236 if (fstatfs(fd, &sfs) < 0)
1237 return;
1238
1239 j->on_network =
1240 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1241 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1242 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1243 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1244 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1245 }
1246
1247 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1248 const char *full, *tilded, *atted;
1249
1250 full = strappenda(prefix, ".journal");
1251 tilded = strappenda(full, "~");
1252 atted = strappenda(prefix, "@");
1253
1254 return streq(filename, full) ||
1255 streq(filename, tilded) ||
1256 startswith(filename, atted);
1257 }
1258
1259 static bool file_type_wanted(int flags, const char *filename) {
1260 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1261 return false;
1262
1263 /* no flags set → every type is OK */
1264 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1265 return true;
1266
1267 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1268 return true;
1269
1270 if (flags & SD_JOURNAL_CURRENT_USER) {
1271 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1272
1273 assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid())
1274 < (int) sizeof(prefix));
1275
1276 if (file_has_type_prefix(prefix, filename))
1277 return true;
1278 }
1279
1280 return false;
1281 }
1282
1283 static int add_any_file(sd_journal *j, const char *path) {
1284 JournalFile *f;
1285 int r;
1286
1287 assert(j);
1288 assert(path);
1289
1290 if (hashmap_get(j->files, path))
1291 return 0;
1292
1293 if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1294 log_warning("Too many open journal files, not adding %s.", path);
1295 return set_put_error(j, -ETOOMANYREFS);
1296 }
1297
1298 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1299 if (r < 0)
1300 return r;
1301
1302 /* journal_file_dump(f); */
1303
1304 r = hashmap_put(j->files, f->path, f);
1305 if (r < 0) {
1306 journal_file_close(f);
1307 return r;
1308 }
1309
1310 log_debug("File %s added.", f->path);
1311
1312 check_network(j, f->fd);
1313
1314 j->current_invalidate_counter ++;
1315
1316 return 0;
1317 }
1318
1319 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1320 _cleanup_free_ char *path = NULL;
1321 int r;
1322
1323 assert(j);
1324 assert(prefix);
1325 assert(filename);
1326
1327 if (j->no_new_files ||
1328 !file_type_wanted(j->flags, filename))
1329 return 0;
1330
1331 path = strjoin(prefix, "/", filename, NULL);
1332 if (!path)
1333 return -ENOMEM;
1334
1335 r = add_any_file(j, path);
1336 if (r == -ENOENT)
1337 return 0;
1338 return 0;
1339 }
1340
1341 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
1342 char *path;
1343 JournalFile *f;
1344
1345 assert(j);
1346 assert(prefix);
1347 assert(filename);
1348
1349 path = strjoin(prefix, "/", filename, NULL);
1350 if (!path)
1351 return -ENOMEM;
1352
1353 f = hashmap_get(j->files, path);
1354 free(path);
1355 if (!f)
1356 return 0;
1357
1358 hashmap_remove(j->files, f->path);
1359
1360 log_debug("File %s removed.", f->path);
1361
1362 if (j->current_file == f) {
1363 j->current_file = NULL;
1364 j->current_field = 0;
1365 }
1366
1367 if (j->unique_file == f) {
1368 j->unique_file = NULL;
1369 j->unique_offset = 0;
1370 }
1371
1372 journal_file_close(f);
1373
1374 j->current_invalidate_counter ++;
1375
1376 return 0;
1377 }
1378
1379 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1380 _cleanup_free_ char *path = NULL;
1381 int r;
1382 _cleanup_closedir_ DIR *d = NULL;
1383 sd_id128_t id, mid;
1384 Directory *m;
1385
1386 assert(j);
1387 assert(prefix);
1388 assert(dirname);
1389
1390 log_debug("Considering %s/%s.", prefix, dirname);
1391
1392 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1393 (sd_id128_from_string(dirname, &id) < 0 ||
1394 sd_id128_get_machine(&mid) < 0 ||
1395 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
1396 return 0;
1397
1398 path = strjoin(prefix, "/", dirname, NULL);
1399 if (!path)
1400 return -ENOMEM;
1401
1402 d = opendir(path);
1403 if (!d) {
1404 log_debug("Failed to open %s: %m", path);
1405 if (errno == ENOENT)
1406 return 0;
1407 return -errno;
1408 }
1409
1410 m = hashmap_get(j->directories_by_path, path);
1411 if (!m) {
1412 m = new0(Directory, 1);
1413 if (!m)
1414 return -ENOMEM;
1415
1416 m->is_root = false;
1417 m->path = path;
1418
1419 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1420 free(m);
1421 return -ENOMEM;
1422 }
1423
1424 path = NULL; /* avoid freeing in cleanup */
1425 j->current_invalidate_counter ++;
1426
1427 log_debug("Directory %s added.", m->path);
1428
1429 } else if (m->is_root)
1430 return 0;
1431
1432 if (m->wd <= 0 && j->inotify_fd >= 0) {
1433
1434 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1435 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1436 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1437 IN_ONLYDIR);
1438
1439 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1440 inotify_rm_watch(j->inotify_fd, m->wd);
1441 }
1442
1443 for (;;) {
1444 struct dirent *de;
1445 union dirent_storage buf;
1446
1447 r = readdir_r(d, &buf.de, &de);
1448 if (r != 0 || !de)
1449 break;
1450
1451 if (dirent_is_file_with_suffix(de, ".journal") ||
1452 dirent_is_file_with_suffix(de, ".journal~")) {
1453 r = add_file(j, m->path, de->d_name);
1454 if (r < 0) {
1455 log_debug("Failed to add file %s/%s: %s",
1456 m->path, de->d_name, strerror(-r));
1457 r = set_put_error(j, r);
1458 if (r < 0)
1459 return r;
1460 }
1461 }
1462 }
1463
1464 check_network(j, dirfd(d));
1465
1466 return 0;
1467 }
1468
1469 static int add_root_directory(sd_journal *j, const char *p) {
1470 _cleanup_closedir_ DIR *d = NULL;
1471 Directory *m;
1472 int r;
1473
1474 assert(j);
1475 assert(p);
1476
1477 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1478 !path_startswith(p, "/run"))
1479 return -EINVAL;
1480
1481 if (j->prefix)
1482 p = strappenda(j->prefix, p);
1483
1484 d = opendir(p);
1485 if (!d)
1486 return -errno;
1487
1488 m = hashmap_get(j->directories_by_path, p);
1489 if (!m) {
1490 m = new0(Directory, 1);
1491 if (!m)
1492 return -ENOMEM;
1493
1494 m->is_root = true;
1495 m->path = strdup(p);
1496 if (!m->path) {
1497 free(m);
1498 return -ENOMEM;
1499 }
1500
1501 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1502 free(m->path);
1503 free(m);
1504 return -ENOMEM;
1505 }
1506
1507 j->current_invalidate_counter ++;
1508
1509 log_debug("Root directory %s added.", m->path);
1510
1511 } else if (!m->is_root)
1512 return 0;
1513
1514 if (m->wd <= 0 && j->inotify_fd >= 0) {
1515
1516 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1517 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1518 IN_ONLYDIR);
1519
1520 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1521 inotify_rm_watch(j->inotify_fd, m->wd);
1522 }
1523
1524 if (j->no_new_files)
1525 return 0;
1526
1527 for (;;) {
1528 struct dirent *de;
1529 union dirent_storage buf;
1530 sd_id128_t id;
1531
1532 r = readdir_r(d, &buf.de, &de);
1533 if (r != 0 || !de)
1534 break;
1535
1536 if (dirent_is_file_with_suffix(de, ".journal") ||
1537 dirent_is_file_with_suffix(de, ".journal~")) {
1538 r = add_file(j, m->path, de->d_name);
1539 if (r < 0) {
1540 log_debug("Failed to add file %s/%s: %s",
1541 m->path, de->d_name, strerror(-r));
1542 r = set_put_error(j, r);
1543 if (r < 0)
1544 return r;
1545 }
1546 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
1547 sd_id128_from_string(de->d_name, &id) >= 0) {
1548
1549 r = add_directory(j, m->path, de->d_name);
1550 if (r < 0)
1551 log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r));
1552 }
1553 }
1554
1555 check_network(j, dirfd(d));
1556
1557 return 0;
1558 }
1559
1560 static int remove_directory(sd_journal *j, Directory *d) {
1561 assert(j);
1562
1563 if (d->wd > 0) {
1564 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1565
1566 if (j->inotify_fd >= 0)
1567 inotify_rm_watch(j->inotify_fd, d->wd);
1568 }
1569
1570 hashmap_remove(j->directories_by_path, d->path);
1571
1572 if (d->is_root)
1573 log_debug("Root directory %s removed.", d->path);
1574 else
1575 log_debug("Directory %s removed.", d->path);
1576
1577 free(d->path);
1578 free(d);
1579
1580 return 0;
1581 }
1582
1583 static int add_search_paths(sd_journal *j) {
1584 int r;
1585 const char search_paths[] =
1586 "/run/log/journal\0"
1587 "/var/log/journal\0";
1588 const char *p;
1589
1590 assert(j);
1591
1592 /* We ignore most errors here, since the idea is to only open
1593 * what's actually accessible, and ignore the rest. */
1594
1595 NULSTR_FOREACH(p, search_paths) {
1596 r = add_root_directory(j, p);
1597 if (r < 0 && r != -ENOENT) {
1598 r = set_put_error(j, r);
1599 if (r < 0)
1600 return r;
1601 }
1602 }
1603
1604 return 0;
1605 }
1606
1607 static int add_current_paths(sd_journal *j) {
1608 Iterator i;
1609 JournalFile *f;
1610
1611 assert(j);
1612 assert(j->no_new_files);
1613
1614 /* Simply adds all directories for files we have open as
1615 * "root" directories. We don't expect errors here, so we
1616 * treat them as fatal. */
1617
1618 HASHMAP_FOREACH(f, j->files, i) {
1619 _cleanup_free_ char *dir;
1620 int r;
1621
1622 dir = dirname_malloc(f->path);
1623 if (!dir)
1624 return -ENOMEM;
1625
1626 r = add_root_directory(j, dir);
1627 if (r < 0) {
1628 set_put_error(j, r);
1629 return r;
1630 }
1631 }
1632
1633 return 0;
1634 }
1635
1636
1637 static int allocate_inotify(sd_journal *j) {
1638 assert(j);
1639
1640 if (j->inotify_fd < 0) {
1641 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1642 if (j->inotify_fd < 0)
1643 return -errno;
1644 }
1645
1646 if (!j->directories_by_wd) {
1647 j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func);
1648 if (!j->directories_by_wd)
1649 return -ENOMEM;
1650 }
1651
1652 return 0;
1653 }
1654
1655 static sd_journal *journal_new(int flags, const char *path) {
1656 sd_journal *j;
1657
1658 j = new0(sd_journal, 1);
1659 if (!j)
1660 return NULL;
1661
1662 j->original_pid = getpid();
1663 j->inotify_fd = -1;
1664 j->flags = flags;
1665 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1666
1667 if (path) {
1668 j->path = strdup(path);
1669 if (!j->path)
1670 goto fail;
1671 }
1672
1673 j->files = hashmap_new(string_hash_func, string_compare_func);
1674 j->directories_by_path = hashmap_new(string_hash_func, string_compare_func);
1675 j->mmap = mmap_cache_new();
1676 if (!j->files || !j->directories_by_path || !j->mmap)
1677 goto fail;
1678
1679 return j;
1680
1681 fail:
1682 sd_journal_close(j);
1683 return NULL;
1684 }
1685
1686 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1687 sd_journal *j;
1688 int r;
1689
1690 assert_return(ret, -EINVAL);
1691 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
1692
1693 j = journal_new(flags, NULL);
1694 if (!j)
1695 return -ENOMEM;
1696
1697 r = add_search_paths(j);
1698 if (r < 0)
1699 goto fail;
1700
1701 *ret = j;
1702 return 0;
1703
1704 fail:
1705 sd_journal_close(j);
1706
1707 return r;
1708 }
1709
1710 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1711 _cleanup_free_ char *root = NULL, *class = NULL;
1712 sd_journal *j;
1713 char *p;
1714 int r;
1715
1716 assert_return(machine, -EINVAL);
1717 assert_return(ret, -EINVAL);
1718 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
1719 assert_return(filename_is_safe(machine), -EINVAL);
1720
1721 p = strappenda("/run/systemd/machines/", machine);
1722 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1723 if (r == -ENOENT)
1724 return -EHOSTDOWN;
1725 if (r < 0)
1726 return r;
1727 if (!root)
1728 return -ENODATA;
1729
1730 if (!streq_ptr(class, "container"))
1731 return -EIO;
1732
1733 j = journal_new(flags, NULL);
1734 if (!j)
1735 return -ENOMEM;
1736
1737 j->prefix = root;
1738 root = NULL;
1739
1740 r = add_search_paths(j);
1741 if (r < 0)
1742 goto fail;
1743
1744 *ret = j;
1745 return 0;
1746
1747 fail:
1748 sd_journal_close(j);
1749 return r;
1750 }
1751
1752 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1753 sd_journal *j;
1754 int r;
1755
1756 assert_return(ret, -EINVAL);
1757 assert_return(path, -EINVAL);
1758 assert_return(flags == 0, -EINVAL);
1759
1760 j = journal_new(flags, path);
1761 if (!j)
1762 return -ENOMEM;
1763
1764 r = add_root_directory(j, path);
1765 if (r < 0) {
1766 set_put_error(j, r);
1767 goto fail;
1768 }
1769
1770 *ret = j;
1771 return 0;
1772
1773 fail:
1774 sd_journal_close(j);
1775
1776 return r;
1777 }
1778
1779 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1780 sd_journal *j;
1781 const char **path;
1782 int r;
1783
1784 assert_return(ret, -EINVAL);
1785 assert_return(flags == 0, -EINVAL);
1786
1787 j = journal_new(flags, NULL);
1788 if (!j)
1789 return -ENOMEM;
1790
1791 STRV_FOREACH(path, paths) {
1792 r = add_any_file(j, *path);
1793 if (r < 0) {
1794 log_error("Failed to open %s: %s", *path, strerror(-r));
1795 goto fail;
1796 }
1797 }
1798
1799 j->no_new_files = true;
1800
1801 *ret = j;
1802 return 0;
1803
1804 fail:
1805 sd_journal_close(j);
1806
1807 return r;
1808 }
1809
1810 _public_ void sd_journal_close(sd_journal *j) {
1811 Directory *d;
1812 JournalFile *f;
1813
1814 if (!j)
1815 return;
1816
1817 sd_journal_flush_matches(j);
1818
1819 while ((f = hashmap_steal_first(j->files)))
1820 journal_file_close(f);
1821
1822 hashmap_free(j->files);
1823
1824 while ((d = hashmap_first(j->directories_by_path)))
1825 remove_directory(j, d);
1826
1827 while ((d = hashmap_first(j->directories_by_wd)))
1828 remove_directory(j, d);
1829
1830 hashmap_free(j->directories_by_path);
1831 hashmap_free(j->directories_by_wd);
1832
1833 if (j->inotify_fd >= 0)
1834 close_nointr_nofail(j->inotify_fd);
1835
1836 if (j->mmap) {
1837 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
1838 mmap_cache_unref(j->mmap);
1839 }
1840
1841 free(j->path);
1842 free(j->prefix);
1843 free(j->unique_field);
1844 set_free(j->errors);
1845 free(j);
1846 }
1847
1848 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1849 Object *o;
1850 JournalFile *f;
1851 int r;
1852
1853 assert_return(j, -EINVAL);
1854 assert_return(!journal_pid_changed(j), -ECHILD);
1855 assert_return(ret, -EINVAL);
1856
1857 f = j->current_file;
1858 if (!f)
1859 return -EADDRNOTAVAIL;
1860
1861 if (f->current_offset <= 0)
1862 return -EADDRNOTAVAIL;
1863
1864 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1865 if (r < 0)
1866 return r;
1867
1868 *ret = le64toh(o->entry.realtime);
1869 return 0;
1870 }
1871
1872 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1873 Object *o;
1874 JournalFile *f;
1875 int r;
1876 sd_id128_t id;
1877
1878 assert_return(j, -EINVAL);
1879 assert_return(!journal_pid_changed(j), -ECHILD);
1880
1881 f = j->current_file;
1882 if (!f)
1883 return -EADDRNOTAVAIL;
1884
1885 if (f->current_offset <= 0)
1886 return -EADDRNOTAVAIL;
1887
1888 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1889 if (r < 0)
1890 return r;
1891
1892 if (ret_boot_id)
1893 *ret_boot_id = o->entry.boot_id;
1894 else {
1895 r = sd_id128_get_boot(&id);
1896 if (r < 0)
1897 return r;
1898
1899 if (!sd_id128_equal(id, o->entry.boot_id))
1900 return -ESTALE;
1901 }
1902
1903 if (ret)
1904 *ret = le64toh(o->entry.monotonic);
1905
1906 return 0;
1907 }
1908
1909 static bool field_is_valid(const char *field) {
1910 const char *p;
1911
1912 assert(field);
1913
1914 if (isempty(field))
1915 return false;
1916
1917 if (startswith(field, "__"))
1918 return false;
1919
1920 for (p = field; *p; p++) {
1921
1922 if (*p == '_')
1923 continue;
1924
1925 if (*p >= 'A' && *p <= 'Z')
1926 continue;
1927
1928 if (*p >= '0' && *p <= '9')
1929 continue;
1930
1931 return false;
1932 }
1933
1934 return true;
1935 }
1936
1937 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1938 JournalFile *f;
1939 uint64_t i, n;
1940 size_t field_length;
1941 int r;
1942 Object *o;
1943
1944 assert_return(j, -EINVAL);
1945 assert_return(!journal_pid_changed(j), -ECHILD);
1946 assert_return(field, -EINVAL);
1947 assert_return(data, -EINVAL);
1948 assert_return(size, -EINVAL);
1949 assert_return(field_is_valid(field), -EINVAL);
1950
1951 f = j->current_file;
1952 if (!f)
1953 return -EADDRNOTAVAIL;
1954
1955 if (f->current_offset <= 0)
1956 return -EADDRNOTAVAIL;
1957
1958 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1959 if (r < 0)
1960 return r;
1961
1962 field_length = strlen(field);
1963
1964 n = journal_file_entry_n_items(o);
1965 for (i = 0; i < n; i++) {
1966 uint64_t p, l;
1967 le64_t le_hash;
1968 size_t t;
1969
1970 p = le64toh(o->entry.items[i].object_offset);
1971 le_hash = o->entry.items[i].hash;
1972 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1973 if (r < 0)
1974 return r;
1975
1976 if (le_hash != o->data.hash)
1977 return -EBADMSG;
1978
1979 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1980
1981 if (o->object.flags & OBJECT_COMPRESSED) {
1982
1983 #ifdef HAVE_XZ
1984 if (uncompress_startswith(o->data.payload, l,
1985 &f->compress_buffer, &f->compress_buffer_size,
1986 field, field_length, '=')) {
1987
1988 uint64_t rsize;
1989
1990 if (!uncompress_blob(o->data.payload, l,
1991 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1992 j->data_threshold))
1993 return -EBADMSG;
1994
1995 *data = f->compress_buffer;
1996 *size = (size_t) rsize;
1997
1998 return 0;
1999 }
2000 #else
2001 return -EPROTONOSUPPORT;
2002 #endif
2003
2004 } else if (l >= field_length+1 &&
2005 memcmp(o->data.payload, field, field_length) == 0 &&
2006 o->data.payload[field_length] == '=') {
2007
2008 t = (size_t) l;
2009
2010 if ((uint64_t) t != l)
2011 return -E2BIG;
2012
2013 *data = o->data.payload;
2014 *size = t;
2015
2016 return 0;
2017 }
2018
2019 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2020 if (r < 0)
2021 return r;
2022 }
2023
2024 return -ENOENT;
2025 }
2026
2027 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2028 size_t t;
2029 uint64_t l;
2030
2031 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2032 t = (size_t) l;
2033
2034 /* We can't read objects larger than 4G on a 32bit machine */
2035 if ((uint64_t) t != l)
2036 return -E2BIG;
2037
2038 if (o->object.flags & OBJECT_COMPRESSED) {
2039 #ifdef HAVE_XZ
2040 uint64_t rsize;
2041
2042 if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold))
2043 return -EBADMSG;
2044
2045 *data = f->compress_buffer;
2046 *size = (size_t) rsize;
2047 #else
2048 return -EPROTONOSUPPORT;
2049 #endif
2050 } else {
2051 *data = o->data.payload;
2052 *size = t;
2053 }
2054
2055 return 0;
2056 }
2057
2058 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2059 JournalFile *f;
2060 uint64_t p, n;
2061 le64_t le_hash;
2062 int r;
2063 Object *o;
2064
2065 assert_return(j, -EINVAL);
2066 assert_return(!journal_pid_changed(j), -ECHILD);
2067 assert_return(data, -EINVAL);
2068 assert_return(size, -EINVAL);
2069
2070 f = j->current_file;
2071 if (!f)
2072 return -EADDRNOTAVAIL;
2073
2074 if (f->current_offset <= 0)
2075 return -EADDRNOTAVAIL;
2076
2077 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2078 if (r < 0)
2079 return r;
2080
2081 n = journal_file_entry_n_items(o);
2082 if (j->current_field >= n)
2083 return 0;
2084
2085 p = le64toh(o->entry.items[j->current_field].object_offset);
2086 le_hash = o->entry.items[j->current_field].hash;
2087 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2088 if (r < 0)
2089 return r;
2090
2091 if (le_hash != o->data.hash)
2092 return -EBADMSG;
2093
2094 r = return_data(j, f, o, data, size);
2095 if (r < 0)
2096 return r;
2097
2098 j->current_field ++;
2099
2100 return 1;
2101 }
2102
2103 _public_ void sd_journal_restart_data(sd_journal *j) {
2104 if (!j)
2105 return;
2106
2107 j->current_field = 0;
2108 }
2109
2110 _public_ int sd_journal_get_fd(sd_journal *j) {
2111 int r;
2112
2113 assert_return(j, -EINVAL);
2114 assert_return(!journal_pid_changed(j), -ECHILD);
2115
2116 if (j->inotify_fd >= 0)
2117 return j->inotify_fd;
2118
2119 r = allocate_inotify(j);
2120 if (r < 0)
2121 return r;
2122
2123 /* Iterate through all dirs again, to add them to the
2124 * inotify */
2125 if (j->no_new_files)
2126 r = add_current_paths(j);
2127 else if (j->path)
2128 r = add_root_directory(j, j->path);
2129 else
2130 r = add_search_paths(j);
2131 if (r < 0)
2132 return r;
2133
2134 return j->inotify_fd;
2135 }
2136
2137 _public_ int sd_journal_get_events(sd_journal *j) {
2138 int fd;
2139
2140 assert_return(j, -EINVAL);
2141 assert_return(!journal_pid_changed(j), -ECHILD);
2142
2143 fd = sd_journal_get_fd(j);
2144 if (fd < 0)
2145 return fd;
2146
2147 return POLLIN;
2148 }
2149
2150 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2151 int fd;
2152
2153 assert_return(j, -EINVAL);
2154 assert_return(!journal_pid_changed(j), -ECHILD);
2155 assert_return(timeout_usec, -EINVAL);
2156
2157 fd = sd_journal_get_fd(j);
2158 if (fd < 0)
2159 return fd;
2160
2161 if (!j->on_network) {
2162 *timeout_usec = (uint64_t) -1;
2163 return 0;
2164 }
2165
2166 /* If we are on the network we need to regularly check for
2167 * changes manually */
2168
2169 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2170 return 1;
2171 }
2172
2173 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2174 Directory *d;
2175 int r;
2176
2177 assert(j);
2178 assert(e);
2179
2180 /* Is this a subdirectory we watch? */
2181 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2182 if (d) {
2183 sd_id128_t id;
2184
2185 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2186 (endswith(e->name, ".journal") ||
2187 endswith(e->name, ".journal~"))) {
2188
2189 /* Event for a journal file */
2190
2191 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2192 r = add_file(j, d->path, e->name);
2193 if (r < 0) {
2194 log_debug("Failed to add file %s/%s: %s",
2195 d->path, e->name, strerror(-r));
2196 set_put_error(j, r);
2197 }
2198
2199 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2200
2201 r = remove_file(j, d->path, e->name);
2202 if (r < 0)
2203 log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
2204 }
2205
2206 } else if (!d->is_root && e->len == 0) {
2207
2208 /* Event for a subdirectory */
2209
2210 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2211 r = remove_directory(j, d);
2212 if (r < 0)
2213 log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
2214 }
2215
2216
2217 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2218
2219 /* Event for root directory */
2220
2221 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2222 r = add_directory(j, d->path, e->name);
2223 if (r < 0)
2224 log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
2225 }
2226 }
2227
2228 return;
2229 }
2230
2231 if (e->mask & IN_IGNORED)
2232 return;
2233
2234 log_warning("Unknown inotify event.");
2235 }
2236
2237 static int determine_change(sd_journal *j) {
2238 bool b;
2239
2240 assert(j);
2241
2242 b = j->current_invalidate_counter != j->last_invalidate_counter;
2243 j->last_invalidate_counter = j->current_invalidate_counter;
2244
2245 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2246 }
2247
2248 _public_ int sd_journal_process(sd_journal *j) {
2249 uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
2250 bool got_something = false;
2251
2252 assert_return(j, -EINVAL);
2253 assert_return(!journal_pid_changed(j), -ECHILD);
2254
2255 j->last_process_usec = now(CLOCK_MONOTONIC);
2256
2257 for (;;) {
2258 struct inotify_event *e;
2259 ssize_t l;
2260
2261 l = read(j->inotify_fd, buffer, sizeof(buffer));
2262 if (l < 0) {
2263 if (errno == EAGAIN || errno == EINTR)
2264 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2265
2266 return -errno;
2267 }
2268
2269 got_something = true;
2270
2271 e = (struct inotify_event*) buffer;
2272 while (l > 0) {
2273 size_t step;
2274
2275 process_inotify_event(j, e);
2276
2277 step = sizeof(struct inotify_event) + e->len;
2278 assert(step <= (size_t) l);
2279
2280 e = (struct inotify_event*) ((uint8_t*) e + step);
2281 l -= step;
2282 }
2283 }
2284
2285 return determine_change(j);
2286 }
2287
2288 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2289 int r;
2290 uint64_t t;
2291
2292 assert_return(j, -EINVAL);
2293 assert_return(!journal_pid_changed(j), -ECHILD);
2294
2295 if (j->inotify_fd < 0) {
2296
2297 /* This is the first invocation, hence create the
2298 * inotify watch */
2299 r = sd_journal_get_fd(j);
2300 if (r < 0)
2301 return r;
2302
2303 /* The journal might have changed since the context
2304 * object was created and we weren't watching before,
2305 * hence don't wait for anything, and return
2306 * immediately. */
2307 return determine_change(j);
2308 }
2309
2310 r = sd_journal_get_timeout(j, &t);
2311 if (r < 0)
2312 return r;
2313
2314 if (t != (uint64_t) -1) {
2315 usec_t n;
2316
2317 n = now(CLOCK_MONOTONIC);
2318 t = t > n ? t - n : 0;
2319
2320 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2321 timeout_usec = t;
2322 }
2323
2324 do {
2325 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2326 } while (r == -EINTR);
2327
2328 if (r < 0)
2329 return r;
2330
2331 return sd_journal_process(j);
2332 }
2333
2334 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2335 Iterator i;
2336 JournalFile *f;
2337 bool first = true;
2338 int r;
2339
2340 assert_return(j, -EINVAL);
2341 assert_return(!journal_pid_changed(j), -ECHILD);
2342 assert_return(from || to, -EINVAL);
2343 assert_return(from != to, -EINVAL);
2344
2345 HASHMAP_FOREACH(f, j->files, i) {
2346 usec_t fr, t;
2347
2348 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2349 if (r == -ENOENT)
2350 continue;
2351 if (r < 0)
2352 return r;
2353 if (r == 0)
2354 continue;
2355
2356 if (first) {
2357 if (from)
2358 *from = fr;
2359 if (to)
2360 *to = t;
2361 first = false;
2362 } else {
2363 if (from)
2364 *from = MIN(fr, *from);
2365 if (to)
2366 *to = MAX(t, *to);
2367 }
2368 }
2369
2370 return first ? 0 : 1;
2371 }
2372
2373 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2374 Iterator i;
2375 JournalFile *f;
2376 bool first = true;
2377 int r;
2378
2379 assert_return(j, -EINVAL);
2380 assert_return(!journal_pid_changed(j), -ECHILD);
2381 assert_return(from || to, -EINVAL);
2382 assert_return(from != to, -EINVAL);
2383
2384 HASHMAP_FOREACH(f, j->files, i) {
2385 usec_t fr, t;
2386
2387 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2388 if (r == -ENOENT)
2389 continue;
2390 if (r < 0)
2391 return r;
2392 if (r == 0)
2393 continue;
2394
2395 if (first) {
2396 if (from)
2397 *from = fr;
2398 if (to)
2399 *to = t;
2400 first = false;
2401 } else {
2402 if (from)
2403 *from = MIN(fr, *from);
2404 if (to)
2405 *to = MAX(t, *to);
2406 }
2407 }
2408
2409 return first ? 0 : 1;
2410 }
2411
2412 void journal_print_header(sd_journal *j) {
2413 Iterator i;
2414 JournalFile *f;
2415 bool newline = false;
2416
2417 assert(j);
2418
2419 HASHMAP_FOREACH(f, j->files, i) {
2420 if (newline)
2421 putchar('\n');
2422 else
2423 newline = true;
2424
2425 journal_file_print_header(f);
2426 }
2427 }
2428
2429 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2430 Iterator i;
2431 JournalFile *f;
2432 uint64_t sum = 0;
2433
2434 assert_return(j, -EINVAL);
2435 assert_return(!journal_pid_changed(j), -ECHILD);
2436 assert_return(bytes, -EINVAL);
2437
2438 HASHMAP_FOREACH(f, j->files, i) {
2439 struct stat st;
2440
2441 if (fstat(f->fd, &st) < 0)
2442 return -errno;
2443
2444 sum += (uint64_t) st.st_blocks * 512ULL;
2445 }
2446
2447 *bytes = sum;
2448 return 0;
2449 }
2450
2451 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2452 char *f;
2453
2454 assert_return(j, -EINVAL);
2455 assert_return(!journal_pid_changed(j), -ECHILD);
2456 assert_return(!isempty(field), -EINVAL);
2457 assert_return(field_is_valid(field), -EINVAL);
2458
2459 f = strdup(field);
2460 if (!f)
2461 return -ENOMEM;
2462
2463 free(j->unique_field);
2464 j->unique_field = f;
2465 j->unique_file = NULL;
2466 j->unique_offset = 0;
2467
2468 return 0;
2469 }
2470
2471 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2472 Object *o;
2473 size_t k;
2474 int r;
2475
2476 assert_return(j, -EINVAL);
2477 assert_return(!journal_pid_changed(j), -ECHILD);
2478 assert_return(data, -EINVAL);
2479 assert_return(l, -EINVAL);
2480 assert_return(j->unique_field, -EINVAL);
2481
2482 k = strlen(j->unique_field);
2483
2484 if (!j->unique_file) {
2485 j->unique_file = hashmap_first(j->files);
2486 if (!j->unique_file)
2487 return 0;
2488 j->unique_offset = 0;
2489 }
2490
2491 for (;;) {
2492 JournalFile *of;
2493 Iterator i;
2494 const void *odata;
2495 size_t ol;
2496 bool found;
2497
2498 /* Proceed to next data object in the field's linked list */
2499 if (j->unique_offset == 0) {
2500 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2501 if (r < 0)
2502 return r;
2503
2504 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2505 } else {
2506 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2507 if (r < 0)
2508 return r;
2509
2510 j->unique_offset = le64toh(o->data.next_field_offset);
2511 }
2512
2513 /* We reached the end of the list? Then start again, with the next file */
2514 if (j->unique_offset == 0) {
2515 JournalFile *n;
2516
2517 n = hashmap_next(j->files, j->unique_file->path);
2518 if (!n)
2519 return 0;
2520
2521 j->unique_file = n;
2522 continue;
2523 }
2524
2525 /* We do not use the type context here, but 0 instead,
2526 * so that we can look at this data object at the same
2527 * time as one on another file */
2528 r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
2529 if (r < 0)
2530 return r;
2531
2532 /* Let's do the type check by hand, since we used 0 context above. */
2533 if (o->object.type != OBJECT_DATA)
2534 return -EBADMSG;
2535
2536 r = return_data(j, j->unique_file, o, &odata, &ol);
2537 if (r < 0)
2538 return r;
2539
2540 /* OK, now let's see if we already returned this data
2541 * object by checking if it exists in the earlier
2542 * traversed files. */
2543 found = false;
2544 HASHMAP_FOREACH(of, j->files, i) {
2545 Object *oo;
2546 uint64_t op;
2547
2548 if (of == j->unique_file)
2549 break;
2550
2551 /* Skip this file it didn't have any fields
2552 * indexed */
2553 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2554 le64toh(of->header->n_fields) <= 0)
2555 continue;
2556
2557 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2558 if (r < 0)
2559 return r;
2560
2561 if (r > 0)
2562 found = true;
2563 }
2564
2565 if (found)
2566 continue;
2567
2568 r = return_data(j, j->unique_file, o, data, l);
2569 if (r < 0)
2570 return r;
2571
2572 return 1;
2573 }
2574 }
2575
2576 _public_ void sd_journal_restart_unique(sd_journal *j) {
2577 if (!j)
2578 return;
2579
2580 j->unique_file = NULL;
2581 j->unique_offset = 0;
2582 }
2583
2584 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2585 assert_return(j, -EINVAL);
2586 assert_return(!journal_pid_changed(j), -ECHILD);
2587
2588 return !j->on_network;
2589 }
2590
2591 static char *lookup_field(const char *field, void *userdata) {
2592 sd_journal *j = userdata;
2593 const void *data;
2594 size_t size, d;
2595 int r;
2596
2597 assert(field);
2598 assert(j);
2599
2600 r = sd_journal_get_data(j, field, &data, &size);
2601 if (r < 0 ||
2602 size > REPLACE_VAR_MAX)
2603 return strdup(field);
2604
2605 d = strlen(field) + 1;
2606
2607 return strndup((const char*) data + d, size - d);
2608 }
2609
2610 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2611 const void *data;
2612 size_t size;
2613 sd_id128_t id;
2614 _cleanup_free_ char *text = NULL, *cid = NULL;
2615 char *t;
2616 int r;
2617
2618 assert_return(j, -EINVAL);
2619 assert_return(!journal_pid_changed(j), -ECHILD);
2620 assert_return(ret, -EINVAL);
2621
2622 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2623 if (r < 0)
2624 return r;
2625
2626 cid = strndup((const char*) data + 11, size - 11);
2627 if (!cid)
2628 return -ENOMEM;
2629
2630 r = sd_id128_from_string(cid, &id);
2631 if (r < 0)
2632 return r;
2633
2634 r = catalog_get(CATALOG_DATABASE, id, &text);
2635 if (r < 0)
2636 return r;
2637
2638 t = replace_var(text, lookup_field, j);
2639 if (!t)
2640 return -ENOMEM;
2641
2642 *ret = t;
2643 return 0;
2644 }
2645
2646 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2647 assert_return(ret, -EINVAL);
2648
2649 return catalog_get(CATALOG_DATABASE, id, ret);
2650 }
2651
2652 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2653 assert_return(j, -EINVAL);
2654 assert_return(!journal_pid_changed(j), -ECHILD);
2655
2656 j->data_threshold = sz;
2657 return 0;
2658 }
2659
2660 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2661 assert_return(j, -EINVAL);
2662 assert_return(!journal_pid_changed(j), -ECHILD);
2663 assert_return(sz, -EINVAL);
2664
2665 *sz = j->data_threshold;
2666 return 0;
2667 }