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