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