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