]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/sd-journal.c
journal: add ability to browse journals of running OS containers
[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, const char *prefix) {
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 (prefix)
1482 p = strappenda(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, const char *prefix) {
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, prefix);
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 int r;
1620 _cleanup_free_ char *dir;
1621
1622 dir = dirname_malloc(f->path);
1623 if (!dir)
1624 return -ENOMEM;
1625
1626 r = add_root_directory(j, dir, NULL);
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, NULL);
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 r = add_search_paths(j, root);
1738 if (r < 0)
1739 goto fail;
1740
1741 *ret = j;
1742 return 0;
1743
1744 fail:
1745 sd_journal_close(j);
1746 return r;
1747 }
1748
1749 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1750 sd_journal *j;
1751 int r;
1752
1753 assert_return(ret, -EINVAL);
1754 assert_return(path, -EINVAL);
1755 assert_return(flags == 0, -EINVAL);
1756
1757 j = journal_new(flags, path);
1758 if (!j)
1759 return -ENOMEM;
1760
1761 r = add_root_directory(j, path, NULL);
1762 if (r < 0) {
1763 set_put_error(j, r);
1764 goto fail;
1765 }
1766
1767 *ret = j;
1768 return 0;
1769
1770 fail:
1771 sd_journal_close(j);
1772
1773 return r;
1774 }
1775
1776 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1777 sd_journal *j;
1778 const char **path;
1779 int r;
1780
1781 assert_return(ret, -EINVAL);
1782 assert_return(flags == 0, -EINVAL);
1783
1784 j = journal_new(flags, NULL);
1785 if (!j)
1786 return -ENOMEM;
1787
1788 STRV_FOREACH(path, paths) {
1789 r = add_any_file(j, *path);
1790 if (r < 0) {
1791 log_error("Failed to open %s: %s", *path, strerror(-r));
1792 goto fail;
1793 }
1794 }
1795
1796 j->no_new_files = true;
1797
1798 *ret = j;
1799 return 0;
1800
1801 fail:
1802 sd_journal_close(j);
1803
1804 return r;
1805 }
1806
1807 _public_ void sd_journal_close(sd_journal *j) {
1808 Directory *d;
1809 JournalFile *f;
1810
1811 if (!j)
1812 return;
1813
1814 sd_journal_flush_matches(j);
1815
1816 while ((f = hashmap_steal_first(j->files)))
1817 journal_file_close(f);
1818
1819 hashmap_free(j->files);
1820
1821 while ((d = hashmap_first(j->directories_by_path)))
1822 remove_directory(j, d);
1823
1824 while ((d = hashmap_first(j->directories_by_wd)))
1825 remove_directory(j, d);
1826
1827 hashmap_free(j->directories_by_path);
1828 hashmap_free(j->directories_by_wd);
1829
1830 if (j->inotify_fd >= 0)
1831 close_nointr_nofail(j->inotify_fd);
1832
1833 if (j->mmap) {
1834 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
1835 mmap_cache_unref(j->mmap);
1836 }
1837
1838 free(j->path);
1839 free(j->unique_field);
1840 set_free(j->errors);
1841 free(j);
1842 }
1843
1844 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1845 Object *o;
1846 JournalFile *f;
1847 int r;
1848
1849 assert_return(j, -EINVAL);
1850 assert_return(!journal_pid_changed(j), -ECHILD);
1851 assert_return(ret, -EINVAL);
1852
1853 f = j->current_file;
1854 if (!f)
1855 return -EADDRNOTAVAIL;
1856
1857 if (f->current_offset <= 0)
1858 return -EADDRNOTAVAIL;
1859
1860 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1861 if (r < 0)
1862 return r;
1863
1864 *ret = le64toh(o->entry.realtime);
1865 return 0;
1866 }
1867
1868 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1869 Object *o;
1870 JournalFile *f;
1871 int r;
1872 sd_id128_t id;
1873
1874 assert_return(j, -EINVAL);
1875 assert_return(!journal_pid_changed(j), -ECHILD);
1876
1877 f = j->current_file;
1878 if (!f)
1879 return -EADDRNOTAVAIL;
1880
1881 if (f->current_offset <= 0)
1882 return -EADDRNOTAVAIL;
1883
1884 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1885 if (r < 0)
1886 return r;
1887
1888 if (ret_boot_id)
1889 *ret_boot_id = o->entry.boot_id;
1890 else {
1891 r = sd_id128_get_boot(&id);
1892 if (r < 0)
1893 return r;
1894
1895 if (!sd_id128_equal(id, o->entry.boot_id))
1896 return -ESTALE;
1897 }
1898
1899 if (ret)
1900 *ret = le64toh(o->entry.monotonic);
1901
1902 return 0;
1903 }
1904
1905 static bool field_is_valid(const char *field) {
1906 const char *p;
1907
1908 assert(field);
1909
1910 if (isempty(field))
1911 return false;
1912
1913 if (startswith(field, "__"))
1914 return false;
1915
1916 for (p = field; *p; p++) {
1917
1918 if (*p == '_')
1919 continue;
1920
1921 if (*p >= 'A' && *p <= 'Z')
1922 continue;
1923
1924 if (*p >= '0' && *p <= '9')
1925 continue;
1926
1927 return false;
1928 }
1929
1930 return true;
1931 }
1932
1933 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1934 JournalFile *f;
1935 uint64_t i, n;
1936 size_t field_length;
1937 int r;
1938 Object *o;
1939
1940 assert_return(j, -EINVAL);
1941 assert_return(!journal_pid_changed(j), -ECHILD);
1942 assert_return(field, -EINVAL);
1943 assert_return(data, -EINVAL);
1944 assert_return(size, -EINVAL);
1945 assert_return(field_is_valid(field), -EINVAL);
1946
1947 f = j->current_file;
1948 if (!f)
1949 return -EADDRNOTAVAIL;
1950
1951 if (f->current_offset <= 0)
1952 return -EADDRNOTAVAIL;
1953
1954 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1955 if (r < 0)
1956 return r;
1957
1958 field_length = strlen(field);
1959
1960 n = journal_file_entry_n_items(o);
1961 for (i = 0; i < n; i++) {
1962 uint64_t p, l;
1963 le64_t le_hash;
1964 size_t t;
1965
1966 p = le64toh(o->entry.items[i].object_offset);
1967 le_hash = o->entry.items[i].hash;
1968 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1969 if (r < 0)
1970 return r;
1971
1972 if (le_hash != o->data.hash)
1973 return -EBADMSG;
1974
1975 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1976
1977 if (o->object.flags & OBJECT_COMPRESSED) {
1978
1979 #ifdef HAVE_XZ
1980 if (uncompress_startswith(o->data.payload, l,
1981 &f->compress_buffer, &f->compress_buffer_size,
1982 field, field_length, '=')) {
1983
1984 uint64_t rsize;
1985
1986 if (!uncompress_blob(o->data.payload, l,
1987 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1988 j->data_threshold))
1989 return -EBADMSG;
1990
1991 *data = f->compress_buffer;
1992 *size = (size_t) rsize;
1993
1994 return 0;
1995 }
1996 #else
1997 return -EPROTONOSUPPORT;
1998 #endif
1999
2000 } else if (l >= field_length+1 &&
2001 memcmp(o->data.payload, field, field_length) == 0 &&
2002 o->data.payload[field_length] == '=') {
2003
2004 t = (size_t) l;
2005
2006 if ((uint64_t) t != l)
2007 return -E2BIG;
2008
2009 *data = o->data.payload;
2010 *size = t;
2011
2012 return 0;
2013 }
2014
2015 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2016 if (r < 0)
2017 return r;
2018 }
2019
2020 return -ENOENT;
2021 }
2022
2023 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2024 size_t t;
2025 uint64_t l;
2026
2027 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2028 t = (size_t) l;
2029
2030 /* We can't read objects larger than 4G on a 32bit machine */
2031 if ((uint64_t) t != l)
2032 return -E2BIG;
2033
2034 if (o->object.flags & OBJECT_COMPRESSED) {
2035 #ifdef HAVE_XZ
2036 uint64_t rsize;
2037
2038 if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold))
2039 return -EBADMSG;
2040
2041 *data = f->compress_buffer;
2042 *size = (size_t) rsize;
2043 #else
2044 return -EPROTONOSUPPORT;
2045 #endif
2046 } else {
2047 *data = o->data.payload;
2048 *size = t;
2049 }
2050
2051 return 0;
2052 }
2053
2054 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2055 JournalFile *f;
2056 uint64_t p, n;
2057 le64_t le_hash;
2058 int r;
2059 Object *o;
2060
2061 assert_return(j, -EINVAL);
2062 assert_return(!journal_pid_changed(j), -ECHILD);
2063 assert_return(data, -EINVAL);
2064 assert_return(size, -EINVAL);
2065
2066 f = j->current_file;
2067 if (!f)
2068 return -EADDRNOTAVAIL;
2069
2070 if (f->current_offset <= 0)
2071 return -EADDRNOTAVAIL;
2072
2073 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2074 if (r < 0)
2075 return r;
2076
2077 n = journal_file_entry_n_items(o);
2078 if (j->current_field >= n)
2079 return 0;
2080
2081 p = le64toh(o->entry.items[j->current_field].object_offset);
2082 le_hash = o->entry.items[j->current_field].hash;
2083 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2084 if (r < 0)
2085 return r;
2086
2087 if (le_hash != o->data.hash)
2088 return -EBADMSG;
2089
2090 r = return_data(j, f, o, data, size);
2091 if (r < 0)
2092 return r;
2093
2094 j->current_field ++;
2095
2096 return 1;
2097 }
2098
2099 _public_ void sd_journal_restart_data(sd_journal *j) {
2100 if (!j)
2101 return;
2102
2103 j->current_field = 0;
2104 }
2105
2106 _public_ int sd_journal_get_fd(sd_journal *j) {
2107 int r;
2108
2109 assert_return(j, -EINVAL);
2110 assert_return(!journal_pid_changed(j), -ECHILD);
2111
2112 if (j->inotify_fd >= 0)
2113 return j->inotify_fd;
2114
2115 r = allocate_inotify(j);
2116 if (r < 0)
2117 return r;
2118
2119 /* Iterate through all dirs again, to add them to the
2120 * inotify */
2121 if (j->no_new_files)
2122 r = add_current_paths(j);
2123 else if (j->path)
2124 r = add_root_directory(j, j->path, NULL);
2125 else
2126 r = add_search_paths(j, NULL);
2127 if (r < 0)
2128 return r;
2129
2130 return j->inotify_fd;
2131 }
2132
2133 _public_ int sd_journal_get_events(sd_journal *j) {
2134 int fd;
2135
2136 assert_return(j, -EINVAL);
2137 assert_return(!journal_pid_changed(j), -ECHILD);
2138
2139 fd = sd_journal_get_fd(j);
2140 if (fd < 0)
2141 return fd;
2142
2143 return POLLIN;
2144 }
2145
2146 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2147 int fd;
2148
2149 assert_return(j, -EINVAL);
2150 assert_return(!journal_pid_changed(j), -ECHILD);
2151 assert_return(timeout_usec, -EINVAL);
2152
2153 fd = sd_journal_get_fd(j);
2154 if (fd < 0)
2155 return fd;
2156
2157 if (!j->on_network) {
2158 *timeout_usec = (uint64_t) -1;
2159 return 0;
2160 }
2161
2162 /* If we are on the network we need to regularly check for
2163 * changes manually */
2164
2165 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2166 return 1;
2167 }
2168
2169 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2170 Directory *d;
2171 int r;
2172
2173 assert(j);
2174 assert(e);
2175
2176 /* Is this a subdirectory we watch? */
2177 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2178 if (d) {
2179 sd_id128_t id;
2180
2181 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2182 (endswith(e->name, ".journal") ||
2183 endswith(e->name, ".journal~"))) {
2184
2185 /* Event for a journal file */
2186
2187 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2188 r = add_file(j, d->path, e->name);
2189 if (r < 0) {
2190 log_debug("Failed to add file %s/%s: %s",
2191 d->path, e->name, strerror(-r));
2192 set_put_error(j, r);
2193 }
2194
2195 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2196
2197 r = remove_file(j, d->path, e->name);
2198 if (r < 0)
2199 log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
2200 }
2201
2202 } else if (!d->is_root && e->len == 0) {
2203
2204 /* Event for a subdirectory */
2205
2206 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2207 r = remove_directory(j, d);
2208 if (r < 0)
2209 log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
2210 }
2211
2212
2213 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2214
2215 /* Event for root directory */
2216
2217 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2218 r = add_directory(j, d->path, e->name);
2219 if (r < 0)
2220 log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
2221 }
2222 }
2223
2224 return;
2225 }
2226
2227 if (e->mask & IN_IGNORED)
2228 return;
2229
2230 log_warning("Unknown inotify event.");
2231 }
2232
2233 static int determine_change(sd_journal *j) {
2234 bool b;
2235
2236 assert(j);
2237
2238 b = j->current_invalidate_counter != j->last_invalidate_counter;
2239 j->last_invalidate_counter = j->current_invalidate_counter;
2240
2241 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2242 }
2243
2244 _public_ int sd_journal_process(sd_journal *j) {
2245 uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
2246 bool got_something = false;
2247
2248 assert_return(j, -EINVAL);
2249 assert_return(!journal_pid_changed(j), -ECHILD);
2250
2251 j->last_process_usec = now(CLOCK_MONOTONIC);
2252
2253 for (;;) {
2254 struct inotify_event *e;
2255 ssize_t l;
2256
2257 l = read(j->inotify_fd, buffer, sizeof(buffer));
2258 if (l < 0) {
2259 if (errno == EAGAIN || errno == EINTR)
2260 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2261
2262 return -errno;
2263 }
2264
2265 got_something = true;
2266
2267 e = (struct inotify_event*) buffer;
2268 while (l > 0) {
2269 size_t step;
2270
2271 process_inotify_event(j, e);
2272
2273 step = sizeof(struct inotify_event) + e->len;
2274 assert(step <= (size_t) l);
2275
2276 e = (struct inotify_event*) ((uint8_t*) e + step);
2277 l -= step;
2278 }
2279 }
2280
2281 return determine_change(j);
2282 }
2283
2284 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2285 int r;
2286 uint64_t t;
2287
2288 assert_return(j, -EINVAL);
2289 assert_return(!journal_pid_changed(j), -ECHILD);
2290
2291 if (j->inotify_fd < 0) {
2292
2293 /* This is the first invocation, hence create the
2294 * inotify watch */
2295 r = sd_journal_get_fd(j);
2296 if (r < 0)
2297 return r;
2298
2299 /* The journal might have changed since the context
2300 * object was created and we weren't watching before,
2301 * hence don't wait for anything, and return
2302 * immediately. */
2303 return determine_change(j);
2304 }
2305
2306 r = sd_journal_get_timeout(j, &t);
2307 if (r < 0)
2308 return r;
2309
2310 if (t != (uint64_t) -1) {
2311 usec_t n;
2312
2313 n = now(CLOCK_MONOTONIC);
2314 t = t > n ? t - n : 0;
2315
2316 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2317 timeout_usec = t;
2318 }
2319
2320 do {
2321 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2322 } while (r == -EINTR);
2323
2324 if (r < 0)
2325 return r;
2326
2327 return sd_journal_process(j);
2328 }
2329
2330 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2331 Iterator i;
2332 JournalFile *f;
2333 bool first = true;
2334 int r;
2335
2336 assert_return(j, -EINVAL);
2337 assert_return(!journal_pid_changed(j), -ECHILD);
2338 assert_return(from || to, -EINVAL);
2339 assert_return(from != to, -EINVAL);
2340
2341 HASHMAP_FOREACH(f, j->files, i) {
2342 usec_t fr, t;
2343
2344 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2345 if (r == -ENOENT)
2346 continue;
2347 if (r < 0)
2348 return r;
2349 if (r == 0)
2350 continue;
2351
2352 if (first) {
2353 if (from)
2354 *from = fr;
2355 if (to)
2356 *to = t;
2357 first = false;
2358 } else {
2359 if (from)
2360 *from = MIN(fr, *from);
2361 if (to)
2362 *to = MAX(t, *to);
2363 }
2364 }
2365
2366 return first ? 0 : 1;
2367 }
2368
2369 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2370 Iterator i;
2371 JournalFile *f;
2372 bool first = true;
2373 int r;
2374
2375 assert_return(j, -EINVAL);
2376 assert_return(!journal_pid_changed(j), -ECHILD);
2377 assert_return(from || to, -EINVAL);
2378 assert_return(from != to, -EINVAL);
2379
2380 HASHMAP_FOREACH(f, j->files, i) {
2381 usec_t fr, t;
2382
2383 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2384 if (r == -ENOENT)
2385 continue;
2386 if (r < 0)
2387 return r;
2388 if (r == 0)
2389 continue;
2390
2391 if (first) {
2392 if (from)
2393 *from = fr;
2394 if (to)
2395 *to = t;
2396 first = false;
2397 } else {
2398 if (from)
2399 *from = MIN(fr, *from);
2400 if (to)
2401 *to = MAX(t, *to);
2402 }
2403 }
2404
2405 return first ? 0 : 1;
2406 }
2407
2408 void journal_print_header(sd_journal *j) {
2409 Iterator i;
2410 JournalFile *f;
2411 bool newline = false;
2412
2413 assert(j);
2414
2415 HASHMAP_FOREACH(f, j->files, i) {
2416 if (newline)
2417 putchar('\n');
2418 else
2419 newline = true;
2420
2421 journal_file_print_header(f);
2422 }
2423 }
2424
2425 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2426 Iterator i;
2427 JournalFile *f;
2428 uint64_t sum = 0;
2429
2430 assert_return(j, -EINVAL);
2431 assert_return(!journal_pid_changed(j), -ECHILD);
2432 assert_return(bytes, -EINVAL);
2433
2434 HASHMAP_FOREACH(f, j->files, i) {
2435 struct stat st;
2436
2437 if (fstat(f->fd, &st) < 0)
2438 return -errno;
2439
2440 sum += (uint64_t) st.st_blocks * 512ULL;
2441 }
2442
2443 *bytes = sum;
2444 return 0;
2445 }
2446
2447 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2448 char *f;
2449
2450 assert_return(j, -EINVAL);
2451 assert_return(!journal_pid_changed(j), -ECHILD);
2452 assert_return(!isempty(field), -EINVAL);
2453 assert_return(field_is_valid(field), -EINVAL);
2454
2455 f = strdup(field);
2456 if (!f)
2457 return -ENOMEM;
2458
2459 free(j->unique_field);
2460 j->unique_field = f;
2461 j->unique_file = NULL;
2462 j->unique_offset = 0;
2463
2464 return 0;
2465 }
2466
2467 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2468 Object *o;
2469 size_t k;
2470 int r;
2471
2472 assert_return(j, -EINVAL);
2473 assert_return(!journal_pid_changed(j), -ECHILD);
2474 assert_return(data, -EINVAL);
2475 assert_return(l, -EINVAL);
2476 assert_return(j->unique_field, -EINVAL);
2477
2478 k = strlen(j->unique_field);
2479
2480 if (!j->unique_file) {
2481 j->unique_file = hashmap_first(j->files);
2482 if (!j->unique_file)
2483 return 0;
2484 j->unique_offset = 0;
2485 }
2486
2487 for (;;) {
2488 JournalFile *of;
2489 Iterator i;
2490 const void *odata;
2491 size_t ol;
2492 bool found;
2493
2494 /* Proceed to next data object in the field's linked list */
2495 if (j->unique_offset == 0) {
2496 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2497 if (r < 0)
2498 return r;
2499
2500 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2501 } else {
2502 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2503 if (r < 0)
2504 return r;
2505
2506 j->unique_offset = le64toh(o->data.next_field_offset);
2507 }
2508
2509 /* We reached the end of the list? Then start again, with the next file */
2510 if (j->unique_offset == 0) {
2511 JournalFile *n;
2512
2513 n = hashmap_next(j->files, j->unique_file->path);
2514 if (!n)
2515 return 0;
2516
2517 j->unique_file = n;
2518 continue;
2519 }
2520
2521 /* We do not use the type context here, but 0 instead,
2522 * so that we can look at this data object at the same
2523 * time as one on another file */
2524 r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
2525 if (r < 0)
2526 return r;
2527
2528 /* Let's do the type check by hand, since we used 0 context above. */
2529 if (o->object.type != OBJECT_DATA)
2530 return -EBADMSG;
2531
2532 r = return_data(j, j->unique_file, o, &odata, &ol);
2533 if (r < 0)
2534 return r;
2535
2536 /* OK, now let's see if we already returned this data
2537 * object by checking if it exists in the earlier
2538 * traversed files. */
2539 found = false;
2540 HASHMAP_FOREACH(of, j->files, i) {
2541 Object *oo;
2542 uint64_t op;
2543
2544 if (of == j->unique_file)
2545 break;
2546
2547 /* Skip this file it didn't have any fields
2548 * indexed */
2549 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2550 le64toh(of->header->n_fields) <= 0)
2551 continue;
2552
2553 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2554 if (r < 0)
2555 return r;
2556
2557 if (r > 0)
2558 found = true;
2559 }
2560
2561 if (found)
2562 continue;
2563
2564 r = return_data(j, j->unique_file, o, data, l);
2565 if (r < 0)
2566 return r;
2567
2568 return 1;
2569 }
2570 }
2571
2572 _public_ void sd_journal_restart_unique(sd_journal *j) {
2573 if (!j)
2574 return;
2575
2576 j->unique_file = NULL;
2577 j->unique_offset = 0;
2578 }
2579
2580 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2581 assert_return(j, -EINVAL);
2582 assert_return(!journal_pid_changed(j), -ECHILD);
2583
2584 return !j->on_network;
2585 }
2586
2587 static char *lookup_field(const char *field, void *userdata) {
2588 sd_journal *j = userdata;
2589 const void *data;
2590 size_t size, d;
2591 int r;
2592
2593 assert(field);
2594 assert(j);
2595
2596 r = sd_journal_get_data(j, field, &data, &size);
2597 if (r < 0 ||
2598 size > REPLACE_VAR_MAX)
2599 return strdup(field);
2600
2601 d = strlen(field) + 1;
2602
2603 return strndup((const char*) data + d, size - d);
2604 }
2605
2606 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2607 const void *data;
2608 size_t size;
2609 sd_id128_t id;
2610 _cleanup_free_ char *text = NULL, *cid = NULL;
2611 char *t;
2612 int r;
2613
2614 assert_return(j, -EINVAL);
2615 assert_return(!journal_pid_changed(j), -ECHILD);
2616 assert_return(ret, -EINVAL);
2617
2618 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2619 if (r < 0)
2620 return r;
2621
2622 cid = strndup((const char*) data + 11, size - 11);
2623 if (!cid)
2624 return -ENOMEM;
2625
2626 r = sd_id128_from_string(cid, &id);
2627 if (r < 0)
2628 return r;
2629
2630 r = catalog_get(CATALOG_DATABASE, id, &text);
2631 if (r < 0)
2632 return r;
2633
2634 t = replace_var(text, lookup_field, j);
2635 if (!t)
2636 return -ENOMEM;
2637
2638 *ret = t;
2639 return 0;
2640 }
2641
2642 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2643 assert_return(ret, -EINVAL);
2644
2645 return catalog_get(CATALOG_DATABASE, id, ret);
2646 }
2647
2648 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2649 assert_return(j, -EINVAL);
2650 assert_return(!journal_pid_changed(j), -ECHILD);
2651
2652 j->data_threshold = sz;
2653 return 0;
2654 }
2655
2656 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2657 assert_return(j, -EINVAL);
2658 assert_return(!journal_pid_changed(j), -ECHILD);
2659 assert_return(sz, -EINVAL);
2660
2661 *sz = j->data_threshold;
2662 return 0;
2663 }