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