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